diff --git a/.hgtags b/.hgtags
index ac3b0728bb51125968bf3df5c97064f097eae4d3..68514aecb65b1fffabea4a531920d9105ee793dc 100644
--- a/.hgtags
+++ b/.hgtags
@@ -108,3 +108,4 @@ d439e94e9a8f99fbfe9a0e61720189185dde1ba1 OpenOLAT 10.2.1
 3003411d7470026b202274abecd2e65c012c9b96 OpenOLAT 10.2.2
 12a83272ceab2dec4ba03903e90a7cddd6cffc2c OpenOLAT 10.2.3
 dddaecac3f7ad507a77d5d2df5ded499b06baf0f OpenOLAT 10.2.4
+aafe04c808cfdd7a75d436dfeabc36e37823b83c OpenOLAT 10.2.5
diff --git a/src/main/java/de/bps/course/nodes/CourseNodePasswordManagerImpl.java b/src/main/java/de/bps/course/nodes/CourseNodePasswordManagerImpl.java
index da8c97bea22d3c723918b445ce17ea3f39da30bf..7929678802ffde58cd112aab83f772a3e85e62f3 100644
--- a/src/main/java/de/bps/course/nodes/CourseNodePasswordManagerImpl.java
+++ b/src/main/java/de/bps/course/nodes/CourseNodePasswordManagerImpl.java
@@ -42,7 +42,7 @@ import org.olat.properties.PropertyManager;
  */
 public class CourseNodePasswordManagerImpl implements CourseNodePasswordManager {
 
-	private Map<Long, AdditionalConditionAnswerContainer> cache = new ConcurrentHashMap<Long, AdditionalConditionAnswerContainer>();
+	private final Map<Long, AdditionalConditionAnswerContainer> cache = new ConcurrentHashMap<Long, AdditionalConditionAnswerContainer>();
 
 	private static CourseNodePasswordManagerImpl INSTANCE;
 	static {
@@ -66,7 +66,9 @@ public class CourseNodePasswordManagerImpl implements CourseNodePasswordManager
 	@Override
 	public AdditionalConditionAnswerContainer getAnswerContainer(Identity identity) {
 		AdditionalConditionAnswerContainer acac = new AdditionalConditionAnswerContainer();
-		if (cache.containsKey(identity.getKey())) {
+		if(identity == null) {
+			//do nothing
+		} else if (cache.containsKey(identity.getKey())) {
 			acac = cache.get(identity.getKey());
 		} else {
 			PropertyManager pm = PropertyManager.getInstance();
diff --git a/src/main/java/de/bps/course/nodes/den/DENManager.java b/src/main/java/de/bps/course/nodes/den/DENManager.java
index b008093fa1e65a50655b53b438d1327c9ec89987..17258bb9c521be13ce23a975a718e7bafe1af0e6 100644
--- a/src/main/java/de/bps/course/nodes/den/DENManager.java
+++ b/src/main/java/de/bps/course/nodes/den/DENManager.java
@@ -199,21 +199,17 @@ public class DENManager {
 		//cancel enroll in calendar entry
 		if(event.getParticipants() != null) {
 			int currLength = event.getParticipants().length;
-			if (currLength > 1) {
+			if (currLength > 0) {
 				//more than one are enrolled
-				String[] partsNew = new String[currLength - 1]; //one to delete
+				List<String> partsNew = new ArrayList<>(currLength); //one to delete
 				String[] partsOld = event.getParticipants();
 				String identityName = identity.getName();
-				for (int i = 0, j = 0; i < partsOld.length; i++) {
-					if ( !(partsOld[i].equals(identityName)) ) {
-						partsNew[j] = partsOld[i];
-						j++; //only increment if new entry was made
+				for (String  partOld:partsOld) {
+					if (!partOld.equals(identityName)) {
+						partsNew.add(partOld);
 					}
 				}
-				event.setParticipants(partsNew);
-			} else if (currLength == 1) {
-				//only one is enrolled, only simple reset needed
-				event.setParticipants(new String[0]);
+				event.setParticipants(partsNew.toArray(new String[partsNew.size()]));
 			}
 			//save calendar event
 			boolean successfullyDone = calManager.updateEventFrom(cal, event);
diff --git a/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java b/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java
index 98feca15c1f41ce6f9778ea9d29792ac3145c801..f8682bd2a5486268665a4d320e1be17c853eae20 100644
--- a/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java
+++ b/src/main/java/de/bps/olat/modules/cl/ChecklistManageCheckpointsController.java
@@ -429,7 +429,7 @@ public class ChecklistManageCheckpointsController extends BasicController {
 	private void openVisitingCard(UserRequest ureq) {
 		
 		removeAsListenerAndDispose(uimc);
-		uimc = new UserInfoMainController(ureq, getWindowControl(), selectedIdentity);
+		uimc = new UserInfoMainController(ureq, getWindowControl(), selectedIdentity, false, false);
 		listenTo(uimc);
 		
 		removeAsListenerAndDispose(cmc);
diff --git a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
index 3a2663649fff49779f650ae67efb8b936d1056a9..fdefd0a6300ee7220864fa7e5745093bf565bc7f 100644
--- a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
+++ b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java
@@ -287,8 +287,9 @@ public class GroupController extends BasicController {
 				if (actionid.equals(COMMAND_VCARD)) {
 					//get identity and open new visiting card controller in new window
 					ControllerCreator userInfoMainControllerCreator = new ControllerCreator() {
+						@Override
 						public Controller createController(UserRequest lureq, WindowControl lwControl) {
-							return new UserInfoMainController(lureq, lwControl, identity);
+							return new UserInfoMainController(lureq, lwControl, identity, true, false);
 						}					
 					};
 					//wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/admin/sysinfo/manager/ThreadInfosManager.java b/src/main/java/org/olat/admin/sysinfo/manager/ThreadInfosManager.java
index 6a2073f20be0d72a477b855643a468fa9f196d4b..6915c5a8d60cf94bb685bfec8d66a2274d909078 100644
--- a/src/main/java/org/olat/admin/sysinfo/manager/ThreadInfosManager.java
+++ b/src/main/java/org/olat/admin/sysinfo/manager/ThreadInfosManager.java
@@ -73,24 +73,26 @@ public class ThreadInfosManager implements Sampler {
     	updateTimeSeries();
 	}
 
-
 	private void updateTimeSeries() {
 		ThreadMXBean threadProxy = ManagementFactory.getThreadMXBean();
 		RuntimeMXBean runtimeProxy  = ManagementFactory.getRuntimeMXBean();
 		ThreadInfo tis[] = threadProxy.dumpAllThreads(false, false);
 
 		List<String> currentThreadNames = new ArrayList<String>();
-		
 		Set<Long> currentThreadIds = new HashSet<Long>();
 		for (ThreadInfo ti : tis) {
-			if (!threadMap.containsKey(ti.getThreadId())) {
+			Long threadId = new Long(ti.getThreadId());
+			if (threadMap.containsKey(threadId)) {
+				ThreadView threadVO = threadMap.get(threadId);
+				threadVO.setState(ti.getThreadState());
+			} else {
 				ThreadView threadVO = new ThreadView();
-				threadVO.setId(ti.getThreadId());
+				threadVO.setId(threadId);
 				threadVO.setName(ti.getThreadName());
 				threadVO.setState(ti.getThreadState());
-				threadMap.put(ti.getThreadId(), threadVO);
+				threadMap.put(threadId, threadVO);
 			}
-			currentThreadIds.add(ti.getThreadId());
+			currentThreadIds.add(threadId);
 		}
 		WorkThreadInformations.currentThreadNames(currentThreadNames);
 		
diff --git a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java
index 9491ac7dd91a8acea379260c83a799d12f123297..7c558fc0b9fe7761773edea823088476195d71dd 100644
--- a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java
+++ b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java
@@ -473,8 +473,9 @@ public class UsermanagerUserSearchController extends BasicController implements
 					int rowid = te.getRowId();
 					final Identity identity = tdm.getObject(rowid);
 					ControllerCreator userInfoMainControllerCreator = new ControllerCreator() {
+						@Override
 						public Controller createController(UserRequest lureq, WindowControl lwControl) {
-							return new UserInfoMainController(lureq, lwControl, identity);
+							return new UserInfoMainController(lureq, lwControl, identity, true, false);
 						}
 					};
 					// wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
index d734808b9b690190de09e3baa45f8f0c79f38f6e..897d015c46d9314f3540c63d01c7a86bde3b6222 100644
--- a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
+++ b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
@@ -386,7 +386,7 @@ public class CourseOverviewController extends BasicController  {
 	
 	private void doOpenEdit(UserRequest ureq, CourseMemberView member) {
 		RepositoryEntry repoEntry = repositoryManager.lookupRepositoryEntry(member.getRepoKey());
-		editSingleMemberCtrl = new EditSingleMembershipController(ureq, getWindowControl(), editedIdentity, repoEntry, null);
+		editSingleMemberCtrl = new EditSingleMembershipController(ureq, getWindowControl(), editedIdentity, repoEntry, null, true);
 		listenTo(editSingleMemberCtrl);
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), editSingleMemberCtrl.getInitialComponent(),
 				true, translate("edit.member"));
diff --git a/src/main/java/org/olat/basesecurity/ui/GroupController.java b/src/main/java/org/olat/basesecurity/ui/GroupController.java
index f4cdea58751e1309087c32b3d5a697d657106435..1100d0807e7bc8617179566b9cdbe87e03ae7180 100644
--- a/src/main/java/org/olat/basesecurity/ui/GroupController.java
+++ b/src/main/java/org/olat/basesecurity/ui/GroupController.java
@@ -286,6 +286,7 @@ public class GroupController extends BasicController {
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
 	 *      org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
 	 */
+	@Override
 	public void event(UserRequest ureq, Controller sourceController, Event event) {
 		if (sourceController == tableCtr) {
 			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
@@ -296,8 +297,9 @@ public class GroupController extends BasicController {
 				if (actionid.equals(COMMAND_VCARD)) {
 					//get identity and open new visiting card controller in new window
 					ControllerCreator userInfoMainControllerCreator = new ControllerCreator() {
+						@Override
 						public Controller createController(UserRequest lureq, WindowControl lwControl) {
-							return new UserInfoMainController(lureq, lwControl, identity);
+							return new UserInfoMainController(lureq, lwControl, identity, true, false);
 						}					
 					};
 					//wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/commons/coordinate/cluster/jms/ClusterEventBus.java b/src/main/java/org/olat/commons/coordinate/cluster/jms/ClusterEventBus.java
index 6a374464e8f23d0e76c3c0f5ba1d51419ea25505..42bacb40554327c512dd04de3a9134b79d857d3f 100644
--- a/src/main/java/org/olat/commons/coordinate/cluster/jms/ClusterEventBus.java
+++ b/src/main/java/org/olat/commons/coordinate/cluster/jms/ClusterEventBus.java
@@ -207,6 +207,7 @@ public class ClusterEventBus extends AbstractEventBus implements MessageListener
 	/**
 	 * this implementation must sum up all counts from all cluster nodes to return the correct number. 
 	 */
+	@Override
 	public int getListeningIdentityCntFor(OLATResourceable ores) {
 		return busInfos.getListenerCountFor(ores);
 	}
@@ -216,18 +217,15 @@ public class ClusterEventBus extends AbstractEventBus implements MessageListener
 	 * @see org.olat.core.util.event.AbstractOLATSystemBus#fireEventToListenersOf(org.olat.core.util.event.MultiUserEvent,
 	 *      org.olat.core.id.OLATResourceable)
 	 */
+	@Override
 	public void fireEventToListenersOf(final MultiUserEvent event, final OLATResourceable ores) {
 		// send the event wrapped over jms to all nodes 
 		// (the receiver will detect whether messages are from itself and thus can be ignored, since they were already sent directly.
 		final long msgId = ++latestSentMsgId;
 		final Integer nodeId = clusterConfig.getNodeId();
 		
-		if(ores != null && ores.getResourceableId() != null
-				&& ores.getResourceableId().equals(0l) && "BusinessGroup".equals(ores.getResourceableTypeName())) {
-			System.out.println();
-		}
-		
 		jmsExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				try {
 					ObjectMessage message = sessionProducer.createObjectMessage();
@@ -260,20 +258,8 @@ public class ClusterEventBus extends AbstractEventBus implements MessageListener
 	 * called by springs org.springframework.jms.listener.DefaultMessageListenerContainer, see coredefaultconfig.xml
 	 * we receive a message here on the topic reserved for olat system bus messages. 
 	 */
+	@Override
 	public void onMessage(Message message) {
-		/*synchronized(incomingMessagesQueue_) {
-			while(incomingMessagesQueue_.size()>LIMIT_ON_INCOMING_MESSAGE_QUEUE) {
-				try {
-					incomingMessagesQueue_.wait();
-				} catch (InterruptedException e) {
-					// this empty catch is okay
-				}
-			}
-			incomingMessagesQueue_.addFirst(message);
-			incomingMessagesQueue_.addFirst(System.currentTimeMillis());
-			incomingMessagesQueue_.notifyAll();
-		}*/
-		
 		try{
 			serveMessage(message, -1);
 		} catch(RuntimeException re) {
@@ -325,13 +311,6 @@ public class ClusterEventBus extends AbstractEventBus implements MessageListener
 			OLATResourceable ores = jmsWrapper.getOres();
 			boolean fromSameNode = clusterConfig.getNodeId().equals(nodeId);
 
-			//TODO jms update nodeinfo statistics, this doesn't work because we remove
-			//all the synchronization in the event bus
-			/* NodeInfo nodeInfo = getNodeInfoFor(nodeId);
-			if (log.isDebug() && !nodeInfo.update(jmsWrapper)) {
-				log.debug("onMessage: update failed. clustereventbus: "+this);
-			}*/
-
 			String recMsg = "received msg: "+(fromSameNode? "[same node]":"")+" from node:" + 
 			nodeId + ", olat-id:" + jmsWrapper.getMsgId() + ", ores:" + ores.getResourceableTypeName() + ":" + ores.getResourceableId() +
 			", event:"+event+"}";
diff --git a/src/main/java/org/olat/commons/coordinate/singlevm/SingleVMEventBus.java b/src/main/java/org/olat/commons/coordinate/singlevm/SingleVMEventBus.java
index a153f7edfa5e249b96349e70dc53694d207534ab..da0d6d9d659ec80176db639c7120c63aaa60998c 100644
--- a/src/main/java/org/olat/commons/coordinate/singlevm/SingleVMEventBus.java
+++ b/src/main/java/org/olat/commons/coordinate/singlevm/SingleVMEventBus.java
@@ -55,7 +55,7 @@ public class SingleVMEventBus extends AbstractEventBus {
 	 * this imple simply counts the identities on this bus.
 	 */
 	public int getListeningIdentityCntFor(OLATResourceable ores) {
-		return getListeningIdentityNamesFor(ores).size();
+		return getLocalListeningIdentityCntFor(ores);
 	}
 
 }
diff --git a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml
index d9bf54d650330cb211db39b8367072f5d42ee360..c2c8b64ba055ab86e912f15f5e2e448b5f7458be 100644
--- a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml
+++ b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml
@@ -4,8 +4,7 @@
 	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
   <class name="org.olat.commons.info.model.InfoMessageImpl" table="o_info_message">
-		<cache usage="transactional" />
-	
+
 		<id name="key" type="long" column="info_id"	unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java b/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
index b58e1958ff6d8217bfc447ec4ea89b8056929356..12e1f6c647888ffed586a5d30a9d5b216c7b3257 100644
--- a/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
+++ b/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
@@ -230,6 +230,7 @@ public class HTMLEditorController extends FormBasicController {
 			// nothing to catch
 		} else if (source == save && lock != null) {
 			doSaveData();
+			newFile = false;//saved, it's not a new file anymore
 		} else if (source == saveClose && lock != null) {
 			doSaveData();
 			fireEvent(ureq, Event.DONE_EVENT);
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappDTabs.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappDTabs.java
index e90c94855f8c3bc2a227f8f906b4a546645eb65a..28d83195b4fa2fc719723e8feb6ddbdab6737a0d 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappDTabs.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappDTabs.java
@@ -21,11 +21,19 @@ package org.olat.core.commons.fullWebApp;
 
 import java.util.List;
 
+import org.olat.NewControllerFactory;
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.dtabs.DTab;
 import org.olat.core.gui.control.generic.dtabs.DTabs;
 import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.BusinessControl;
+import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.HistoryPoint;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
 
 /**
  * 
@@ -35,6 +43,8 @@ import org.olat.core.id.context.ContextEntry;
  */
 class BaseFullWebappDTabs implements DTabs {
 	
+	private static final OLog log = Tracing.createLoggerFor(BaseFullWebappDTabs.class);
+	
 	private final BaseFullWebappController webappCtrl;
 	
 	public BaseFullWebappDTabs(BaseFullWebappController webappCtrl) {
@@ -70,4 +80,32 @@ class BaseFullWebappDTabs implements DTabs {
 	public void removeDTab(UserRequest ureq, DTab dt) {
 		webappCtrl.removeDTab(ureq, dt);
 	}
+
+	@Override
+	public void closeDTab(UserRequest ureq, OLATResourceable ores, HistoryPoint launchedFromPoint) {
+		// Now try to go back to place that is attached to (optional) root back business path
+		if (launchedFromPoint != null && StringHelper.containsNonWhitespace(launchedFromPoint.getBusinessPath())
+				&& launchedFromPoint.getEntries() != null && launchedFromPoint.getEntries().size() > 0) {
+			BusinessControl bc = BusinessControlFactory.getInstance().createFromPoint(launchedFromPoint);
+			if(bc.hasContextEntry()) {
+				WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, webappCtrl.getWindowControl());
+				try {
+					//make the resume secure. If something fail, don't generate a red screen
+					NewControllerFactory.getInstance().launch(ureq, bwControl);
+				} catch (Exception e) {
+					log.error("Error while resuming with root level back business path::" + launchedFromPoint.getBusinessPath(), e);
+				}
+			}
+		}
+		
+		// Navigate beyond the stack, our own layout has been popped - close this tab
+		DTabs tabs = webappCtrl.getWindowControl().getWindowBackOffice().getWindow().getDTabs();
+		if (tabs != null) {
+			
+			DTab tab = tabs.getDTab(ores);
+			if (tab != null) {
+				tabs.removeDTab(ureq, tab);						
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index 58e94283bac6ed2cceee8478f4a3bc4cb562bd27..b36eaa7ebfc930d09845a66beec2ad25deec0270 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -28,7 +28,6 @@
 		<mapping-file>org/olat/resource/accesscontrol/model/AccessTransaction.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/model/OfferAccess.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/model/Order.hbm.xml</mapping-file>
-		<mapping-file>org/olat/resource/accesscontrol/model/Reservation.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/provider/paypal/model/PaypalAccessMethod.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/provider/paypal/model/PaypalTransaction.hbm.xml</mapping-file>
 		<mapping-file>org/olat/basesecurity/AuthenticationImpl.hbm.xml</mapping-file>
@@ -106,6 +105,7 @@
 		<class>org.olat.course.nodes.cl.model.DBCheckbox</class>
 		<class>org.olat.course.nodes.cl.model.DBCheck</class>
 		<class>org.olat.course.nodes.gta.model.TaskImpl</class>
+		<class>org.olat.course.nodes.gta.model.TaskLightImpl</class>
 		<class>org.olat.course.nodes.gta.model.TaskListImpl</class>
 		<class>org.olat.course.certificate.model.CertificateImpl</class>
 		<class>org.olat.course.certificate.model.CertificateStandalone</class>
@@ -122,6 +122,7 @@
 		<class>org.olat.repository.model.RepositoryEntryLightImpl</class>
 		<class>org.olat.repository.model.RepositoryEntryMembership</class>
 		<class>org.olat.resource.references.ReferenceImpl</class>
+		<class>org.olat.resource.accesscontrol.model.ResourceReservationImpl</class>
 		<class>org.olat.instantMessaging.model.InstantMessageImpl</class>
 		<class>org.olat.instantMessaging.model.ImPreferencesImpl</class>
 		<class>org.olat.instantMessaging.model.RosterEntryImpl</class>
diff --git a/src/main/java/org/olat/core/commons/services/mark/impl/MarkImpl.hbm.xml b/src/main/java/org/olat/core/commons/services/mark/impl/MarkImpl.hbm.xml
index f6ad34f10b470b5aaaa3a60916bb52b0686f6b60..cc0a96221078ffa5bbe52f82a71bcd8531cbb0a7 100644
--- a/src/main/java/org/olat/core/commons/services/mark/impl/MarkImpl.hbm.xml
+++ b/src/main/java/org/olat/core/commons/services/mark/impl/MarkImpl.hbm.xml
@@ -4,8 +4,7 @@
 	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
   <class name="org.olat.core.commons.services.mark.impl.MarkImpl" table="o_mark">
-		<cache usage="transactional" />
-	
+
 		<id name="key" type="long" column="mark_id"	unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/core/commons/services/tagging/model/TagImpl.hbm.xml b/src/main/java/org/olat/core/commons/services/tagging/model/TagImpl.hbm.xml
index 8925334433099ee09d8e2ed57c20153bafc98f9f..42916092e1f401802c92754e2344fcfdfb2fc190 100644
--- a/src/main/java/org/olat/core/commons/services/tagging/model/TagImpl.hbm.xml
+++ b/src/main/java/org/olat/core/commons/services/tagging/model/TagImpl.hbm.xml
@@ -4,8 +4,7 @@
 	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
   <class name="org.olat.core.commons.services.tagging.model.TagImpl" table="o_tag">
-		<cache usage="transactional" />
-	
+		
 		<id name="key" type="long" column="tag_id"	unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
index e50f08f15608f70de7fc1bcf9030e2831eeb15a9..396f52e6885c472dab7e047dabf5f20b39b0487c 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
@@ -756,6 +756,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 				if(StringHelper.containsNonWhitespace(selectedRowIndex)) {
 					doSelect(ureq, col.getAction(), Integer.parseInt(selectedRowIndex));
 					select = true;
+					break;
 				}
 			}
 		}
@@ -1106,7 +1107,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 			doSearch(ureq, search, null);
 			getRootForm().fireFormEvent(ureq, new FlexiTableEvent(this, search));
 		} else {
-			doResetSearch();
+			doResetSearch(ureq);
 		}
 	}
 	
@@ -1187,13 +1188,15 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 		return Arrays.equals(orderBy , sortKeys);
 	}
 	
-	protected void doResetSearch() {
+	protected void doResetSearch(UserRequest ureq) {
 		conditionalQueries = null;
 		currentPage = 0;
 		if(dataSource != null) {
 			resetInternComponents();
 			dataSource.clear();
 			dataSource.load(null, null, 0, getPageSize());
+		} else {
+			getRootForm().fireFormEvent(ureq, new FlexiTableSearchEvent(this, FormEvent.ONCLICK));
 		}
 	}
 
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableSearchEvent.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableSearchEvent.java
index b143334c07c773a9eda08b3c3bdf30dc1c8244c8..43b24745e495cd317b9b8d561e1dc29b9f058a60 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableSearchEvent.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableSearchEvent.java
@@ -33,16 +33,23 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 public class FlexiTableSearchEvent extends FormEvent {
 
 	private static final long serialVersionUID = -1977791683080030187L;
-	public static final String CMD = "ftSearch";
+	public static final String SEARCH = "ftSearch";
+	public static final String RESET = "ftResetSearch";
 
 	private final String search;
 	private final List<String> condQueries;
 
 	public FlexiTableSearchEvent(FormItem source, String search, List<String> condQueries, int action) {
-		super(CMD, source, action);
+		super(SEARCH, source, action);
 		this.search = search;
 		this.condQueries = condQueries;
 	}
+	
+	public FlexiTableSearchEvent(FormItem source, int action) {
+		super(RESET, source, action);
+		this.search = null;
+		this.condQueries = null;
+	}
 
 	public String getSearch() {
 		return search;
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
index e613fa34d2a1779d2530eb3c255760502264c662..f2cb4f22ffb20874b48a9aff35449d6c4286da3a 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
@@ -68,6 +68,10 @@ public class SortableFlexiTableModelDelegate<T> {
 		return columnIndex;
 	}
 	
+	public Collator getCollator() {
+		return collator;
+	}
+	
 	public List<T> sort() {
 		int rowCount = tableModel.getRowCount();
 		List<T> rows = new ArrayList<>(rowCount);
diff --git a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
index 4658cbc2537ca9395a14663744a64f5217842e79..7ba83e45a634f9ad18cd6647e2771d1082401f3f 100644
--- a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
+++ b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
@@ -31,6 +31,7 @@ import java.util.List;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.HistoryPoint;
 
 /**
  * Description:<br>
@@ -79,6 +80,14 @@ public interface DTabs {
 	 * @param dt Remove this tab
 	 */
 	public void removeDTab(UserRequest ureq, DTab dt);
+	
+	/**
+	 * 
+	 * @param ureq
+	 * @param tab
+	 * @param lastPoint
+	 */
+	public void closeDTab(UserRequest ureq, OLATResourceable ores, HistoryPoint lastPoint);
 		
 	
 }
diff --git a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
index 28b432e4517d25ff558095f1fafa47d059d95fc3..ea021d08a59bed90dd28dfb3bf2e871ca1bc0a6e 100644
--- a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
+++ b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
@@ -358,7 +358,7 @@ public class VelocityRenderDecorator implements Closeable {
 			if(url != null) {
 				sb.append("<span class=\"o_chelp_wrapper\">")
 				  .append("<a href=\"").append(url)
-				  .append("\" class=\"o_chelp\"><i class='o_icon o_icon_help'></i> ")
+				  .append("\" class=\"o_chelp\" target=\"_blank\"><i class='o_icon o_icon_help'></i> ")
 				  .append(renderer.getTranslator().translate("help"))
 				  .append("</a></span>");
 			}
diff --git a/src/main/java/org/olat/core/id/context/BusinessControlFactory.java b/src/main/java/org/olat/core/id/context/BusinessControlFactory.java
index 545f7d2217c1e4d992771347ba35aed2005f980d..7000806bd191cbfc73ee37349b708f138bd3b421 100644
--- a/src/main/java/org/olat/core/id/context/BusinessControlFactory.java
+++ b/src/main/java/org/olat/core/id/context/BusinessControlFactory.java
@@ -176,7 +176,6 @@ public class BusinessControlFactory {
 	 * @param wControl
 	 * @return
 	 */
-	//fxdiff BAKS-7 Resume function
 	public WindowControl createBusinessWindowControl(final OLATResourceable ores, StateEntry state, WindowControl wControl) {
 		WindowControl bwControl;
 		ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(ores);
@@ -196,7 +195,6 @@ public class BusinessControlFactory {
 	 * @param wControl
 	 * @return
 	 */
-	//fxdiff BAKS-7 Resume function
 	public WindowControl createBusinessWindowControl(UserRequest ureq, final OLATResourceable ores, StateEntry state,
 			WindowControl wControl, boolean addToHistory) {
 		WindowControl bwControl = createBusinessWindowControl(ores, state, wControl);
@@ -206,7 +204,6 @@ public class BusinessControlFactory {
 		return bwControl;
 	}
 	
-	//fxdiff BAKS-7 Resume function
 	public void addToHistory(UserRequest ureq, WindowControl wControl) {
 		if(wControl == null || wControl.getBusinessControl() == null) return;
 		ureq.getUserSession().addToHistory(ureq, wControl.getBusinessControl());
@@ -485,8 +482,7 @@ public class BusinessControlFactory {
 		}
 		return date;
 	}
-	
-	//fxdiff BAKS-7 Resume function
+
 	public String getPath(ContextEntry entry) {
 		String path = entry.getOLATResourceable().getResourceableTypeName();
 		path = path.endsWith(":0") ? path.substring(0, path.length() - 2) : path;
@@ -575,7 +571,6 @@ class MyContextEntry implements ContextEntry, Serializable {
 	private static final long serialVersionUID = 949522581806327579L;
 	private OLATResourceable olatResourceable;
 
-	//fxdiff BAKS-7 Resume function
 	private StateEntry state;
 
 	MyContextEntry(OLATResourceable ores) {
@@ -595,13 +590,11 @@ class MyContextEntry implements ContextEntry, Serializable {
 	}
 
 	@Override
-	//fxdiff BAKS-7 Resume function
 	public StateEntry getTransientState() {
 		return state;
 	}
 
 	@Override
-	//fxdiff BAKS-7 Resume function
 	public void setTransientState(StateEntry state) {
 		this.state = state;
 	}
diff --git a/src/main/java/org/olat/core/util/event/AbstractEventBus.java b/src/main/java/org/olat/core/util/event/AbstractEventBus.java
index 8fa2b0f457ba2eabdc7db46db50dd6a1e678fb84..9d92297a63e37f03eb755567c6193602207b8b63 100644
--- a/src/main/java/org/olat/core/util/event/AbstractEventBus.java
+++ b/src/main/java/org/olat/core/util/event/AbstractEventBus.java
@@ -24,15 +24,19 @@
 */
 package org.olat.core.util.event;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
+import java.util.WeakHashMap;
 
+import org.olat.core.gui.control.Controller;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
+import org.olat.core.logging.activity.UserActivityLoggerImpl;
 import org.olat.core.util.event.businfo.BusListenerInfo;
 
 /**
@@ -41,32 +45,67 @@ import org.olat.core.util.event.businfo.BusListenerInfo;
  */
 public abstract class AbstractEventBus implements EventBus {
 
-	private Map<String, EventAgency> infocenter;
-	private Map<String, EventAgency> typeInfocenter;
-	private OLog log = Tracing.createLoggerFor(this.getClass());
+	private final Map<String, EventAgency> infocenter;
+	private final Map<String, EventAgency> typeInfocenter;
+	private final OLog log = Tracing.createLoggerFor(this.getClass());
 
 	public AbstractEventBus() {
 		infocenter = new HashMap<String, EventAgency>();
 		typeInfocenter = new HashMap<String, EventAgency>();
 	}
 
+	@Override
 	public void registerFor(GenericEventListener gel, Identity identity, OLATResourceable ores) {
-		EventAgency ea = getEventAgencyFor(ores);
-		ea.addListener(gel, identity);
+		final Long oresId = ores.getResourceableId();
+		final String typeName = ores.getResourceableTypeName();
+		synchronized (infocenter) {
+			EventAgency ea = null;
+			if (oresId == null) {
+				// return the eventagency which listens to all events with the type of
+				// the ores
+				ea = typeInfocenter.get(typeName);
+				if (ea == null) { // we are the first listener -> create an agency
+					ea = new EventAgency();
+					typeInfocenter.put(typeName, ea);
+				}
+			} else {
+				// type and id
+				String oresStr = typeName + "::" + oresId;
+				ea = infocenter.get(oresStr);
+				if (ea == null) { // we are the first listener
+					ea = new EventAgency();
+					infocenter.put(oresStr, ea);
+				}
+			}
+			ea.addListener(gel, identity);
+		}
 	}
 
+	@Override
 	public void deregisterFor(GenericEventListener gel, OLATResourceable ores) {
-		EventAgency ea = getEventAgencyFor(ores);
-		ea.removeListener(gel);
-	}
-
-	/**
-	 * @return the listening names on a resource - only use for admin purposes!
-	 */
-	public Set<String> getListeningIdentityNamesFor(OLATResourceable ores) {
-		EventAgency ea = getEventAgencyFor(ores);
-		Set<String> s = ea.getListeningIdentityNames();
-		return s;
+		final Long oresId = ores.getResourceableId();
+		final String typeName = ores.getResourceableTypeName();
+		synchronized (infocenter) {
+			if (oresId == null) {
+				EventAgency ea = typeInfocenter.get(typeName);
+				if (ea != null) {
+					ea.removeListener(gel);
+					if(ea.getListenerCount() == 0) {
+						typeInfocenter.remove(typeName);
+					}
+				}
+			} else {
+				// type and id
+				String oresStr = typeName + "::" + oresId;
+				EventAgency ea = infocenter.get(oresStr);
+				if (ea != null) {
+					ea.removeListener(gel);
+					if(ea.getListenerCount() == 0) {
+						typeInfocenter.remove(typeName);
+					}
+				}
+			}
+		}
 	}
 
 	public abstract int getListeningIdentityCntFor(OLATResourceable ores);
@@ -79,107 +118,160 @@ public abstract class AbstractEventBus implements EventBus {
 	 * @param event
 	 * @param ores
 	 */
-	protected void doFire(MultiUserEvent event, OLATResourceable ores) {
-		Long oresId = ores.getResourceableId();
-		String typeName = ores.getResourceableTypeName();
+	protected final void doFire(final MultiUserEvent event, final OLATResourceable ores) {
+		final Long oresId = ores.getResourceableId();
+		final String typeName = ores.getResourceableTypeName();
 
-		// 1. fire to all instance listeners
-		if (oresId != null) {
-			// fire event to all id - listeners
-			
-			//try to avoid synchronize on infocenter over next two codelines
-			//see OLAT-3681 -
-			EventAgency ea = getEventAgencyFor(typeName, oresId);//synchronizes shortly on infocenter
-			ea.fireEvent(event);//synchronizes short on listeners but only to copy
+		GenericEventListener[] liArr = null;
+		synchronized (infocenter) {  
+			if (oresId == null) {
+				EventAgency ea = typeInfocenter.get(typeName);
+				if (ea != null) { // we are the first listener -> create an agency
+					liArr = ea.getListeners();
+				}
+			} else {
+				String oresStr = typeName + "::" + oresId;
+				EventAgency ea = infocenter.get(oresStr);
+				if (ea != null) {
+					liArr = ea.getListeners();
+				}
+			}
 		}
 		
-		//try to avoid synchronize on infocenter over next two codelines
-		//see OLAT-3681
-		// 2. fire event to all type - listeners
-		EventAgency tea = getEventAgencyFor(typeName, null);
-		if (log.isDebug()) log.debug("Generic Event from: "+typeName+": of type: "+event.getClass().getName());
-		tea.fireEvent(event);//synchronizes short on listeners but only to copy
-	}
-	
-	/**
-	 * used only for monitoring purposes
-	 */
-	public Map<String, EventAgency> getUnmodifiableInfoCenter() {
-		synchronized (infocenter) {  //o_clusterOK by:fj
-			Map<String, EventAgency> all = new HashMap<String, EventAgency>(infocenter.size() + typeInfocenter.size());
-			all.putAll(infocenter);
-			all.putAll(typeInfocenter);
-			return all;
+		if(liArr != null) {
+			for (int i = 0; i < liArr.length; i++) {
+				try {
+					final GenericEventListener listener = liArr[i];
+					
+					//make sure GenericEvents are only sent when controller is not yet disposed
+					if (listener instanceof Controller) {
+						Controller dCtrl = (Controller)listener;
+						if (!dCtrl.isDisposed()) {
+							ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(new Runnable() {
+								public void run() {
+									listener.event(event);
+								}
+							}, UserActivityLoggerImpl.newLoggerForEventBus(dCtrl));
+						}
+					} else if(listener != null) {
+						if(log.isDebug()){
+							log.debug("fireEvent: Non-Controller: "+listener);
+						}
+						//is there a need to differ the events sent on one VM and in cluster mode?
+						ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(new Runnable() {
+							public void run() {
+								listener.event(event);
+							}
+						}, ThreadLocalUserActivityLoggerInstaller.createEmptyUserActivityLogger());
+					}
+				} catch (RuntimeException e) {
+					log.error("Error while sending generic event: "+liArr[i], e);
+				}
+			}
 		}
 	}
 	
-	protected BusListenerInfo createBusListenerInfo() {
+	protected final BusListenerInfo createBusListenerInfo() {
 		BusListenerInfo bii = new BusListenerInfo();
 		synchronized(infocenter) { // o_clusterOK by:fj: extract quickly so that we can later serialize and send across the wire. data affects only one vm.
 			// for all types: the name of the type + "::"+ the id (integer) is used as key
-			for (Entry<String, EventAgency> entry: infocenter.entrySet()) {
-				String derivedOres = entry.getKey();
-				int cnt = entry.getValue().getListenerCount();
+			List<String> infocenterKeys = new ArrayList<>(infocenter.keySet());
+			for (String derivedOres: infocenterKeys) {
+				EventAgency ea = infocenter.get(derivedOres);
+				int cnt = ea.getListenerCount();
 				// only add those with at least one current listener. Telling that a resource has no listeners is unneeded since we update 
 				// the whole table on each clusterInfoEvent (cluster:: could be improved by only sending the delta of listeners)
-				if (cnt > 0) bii.addEntry(derivedOres, cnt);
+				if (cnt > 0) {
+					bii.addEntry(derivedOres, cnt);
+				} else {
+					infocenter.remove(derivedOres);
+				}
 			}
+			infocenterKeys = null;
+			
 			// for all types: the name of the type is used as key
-			for (Entry<String, EventAgency> entry: typeInfocenter.entrySet()) {
-				String derivedOres = entry.getKey();
-				int cnt = entry.getValue().getListenerCount();
-				if (cnt > 0) bii.addEntry(derivedOres, cnt);
+			List<String> typeInfocenterKeys = new ArrayList<>(typeInfocenter.keySet());
+			for (String derivedOres: typeInfocenterKeys) {
+				EventAgency ea = typeInfocenter.get(derivedOres);
+				int cnt = ea.getListenerCount();
+				if (cnt > 0) {
+					bii.addEntry(derivedOres, cnt);
+				} else {
+					typeInfocenter.remove(derivedOres);
+				}
 			}
 		}
 		return bii;
 	}
-
-	private EventAgency getEventAgencyFor(OLATResourceable ores) {
-		Long oresId = ores.getResourceableId();
-		String typeName = ores.getResourceableTypeName();
-		return getEventAgencyFor(typeName, oresId);
-	}
-
-	private EventAgency getEventAgencyFor(String typeName, Long oresId) {
-		EventAgency ea;
-		synchronized (infocenter) {  
-			//o_clusterOK by:fj for cluster: clustereventbus is async vm to vm, and 
-			// here we only the eventagency of one vm need to be synchronized
+	
+	protected final int getLocalListeningIdentityCntFor(OLATResourceable ores) {
+		int cnt = 0;
+		final Long oresId = ores.getResourceableId();
+		final String typeName = ores.getResourceableTypeName();
+		synchronized (infocenter) { 
+			EventAgency ea = null;
 			if (oresId == null) {
-				// return the eventagency which listens to all events with the type of
-				// the ores
-				ea = typeInfocenter.get(typeName);
-				if (ea == null) { // we are the first listener -> create an agency
-					ea = new EventAgency();
-					typeInfocenter.put(typeName, ea);
-				}
+				ea = typeInfocenter.get(typeName);	
 			} else {
 				// type and id
-				String oresStr = typeName + "::" + oresId.toString();
+				String oresStr = typeName + "::" + oresId;
 				ea = infocenter.get(oresStr);
-				if (ea == null) { // we are the first listener
-					ea = new EventAgency();
-					infocenter.put(oresStr, ea);
-				}
+			}
+			if (ea != null) {
+				cnt = ea.getListenerCount();
 			}
 		}
-		return ea;
+		return cnt;
 	}
 	
-	public String toString() {
+	/**
+	 * Description: <br>
+	 * The listeners map is not synchronized, but need to be. The synchronization
+	 * is done by the infocenter map. Make sure that you always access instances of
+	 * this class in a synchronized(infocenter).
+	 * 
+	 * @author Felix Jost
+	 * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+	 */
+	private static class EventAgency {
+		private WeakHashMap<GenericEventListener, String> listeners = new WeakHashMap<GenericEventListener, String>();
 		
-		if (log.isDebug()) {
-			int totalListenerCount = 0;
-			for (Entry<String, EventAgency> entry: getUnmodifiableInfoCenter().entrySet()) {
-				EventAgency eventAgency = entry.getValue();
-				int listenerCount = eventAgency.getListenerCount();
-				//if (listenerCount > 0)
-				//System.out.println("TEST AbstractEventBus  derivedOres(key)=" + entry.getKey() + "  listenerCount=" + listenerCount);
-				totalListenerCount = totalListenerCount + listenerCount;
+		/**
+		 * @param event
+		 */
+		GenericEventListener[] getListeners() {
+			return listeners.keySet().toArray(new GenericEventListener[listeners.size()]);
+		}
+
+		/**
+		 * impl note: the underlying impl takes a weakHashMap, so unused entries are
+		 * cleared. an instance may not be added twice (make no sense anyway), since we
+		 * are using a map, not a list.
+		 * 
+		 * @param gel the instance which wants to listen to events.
+		 * @param identity the identity belonging to the listener, or null if there is
+		 *          none (e.g. the LockManager = the 'System')
+		 */
+		void addListener(GenericEventListener gel, Identity identity) {
+			if (!listeners.containsKey(gel)) {
+				String identityName = (identity != null? identity.getName() : null);
+				listeners.put(gel, identityName);
 			}
-			return "AbstractEventBus : #totalListenerCount=" + totalListenerCount + "   #EventAgency of infocenter=" + infocenter.size() + " #EventAgency of  typeInfocenter=" + typeInfocenter.size();
-		} 
-		return "Enable debugging to see number of listeners"; 
-	}
+		}
 
+		/**
+		 * @param gel
+		 */
+		void removeListener(GenericEventListener gel) {
+			listeners.remove(gel);
+		}
+		
+		/**
+		 * 
+		 * @return the current number of listeners listening to this channel/eventagency 
+		 */
+		int getListenerCount() {
+			return listeners.size();	
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/event/EventAgency.java b/src/main/java/org/olat/core/util/event/EventAgency.java
deleted file mode 100644
index 6019d8abd787e60d895715a629aa3bc7db2ebba7..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/event/EventAgency.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <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
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <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>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.  
-* <p>
-*/ 
-
-package org.olat.core.util.event;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.WeakHashMap;
-
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.id.Identity;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
-import org.olat.core.logging.activity.UserActivityLoggerImpl;
-
-/**
- * Description: <br>
- * note: need to sync on each method since the hashmap is not synced itself and
- * also to ensure listeners.values() does not break with a
- * concurrentmodificationexception (weakhashmap has fail-fast iterators, but
- * read-only operation do not trigger removing entries from the referencequeue.
- * 
- * @author Felix Jost
- */
-class EventAgency {
-	private WeakHashMap<GenericEventListener, String> listeners = new WeakHashMap<GenericEventListener, String>();
-	private OLog log = Tracing.createLoggerFor(this.getClass());
-
-	//private Event latestEvent = null;
-	//private long latestEventTimestamp; // ts when the latest event was fired
-	//private long ttl = 0; // time-to-live in miliseconds
-	
-	EventAgency() {
-		//
-	}
-	
-	
-	/**
-	 * @param ttl The time-to-live to set, in miliseconds. the latest event fired will be kept "in store" for that period in time and will be delivered upon registering. defaults to 0, meaning that the latest event is never stored.
-	 */
-	/*EventAgency(long ttl) {
-		this.ttl = ttl;
-	}*/
-
-	/**
-	 * 
-	 * 
-	 * @param event
-	 */
-	void fireEvent(final Event event) {
-		GenericEventListener[] liArr;
-		synchronized (listeners) {  //o_clusterOK by:fj
-			// needed to avoid concurrentmodificationexception, since the recipients may remove themselves from the list and the listeners lock is reentrant
-			List<GenericEventListener> li = new ArrayList<GenericEventListener>(listeners.keySet());
-			// instead synchronize looping to avoid concurrent modifcation exception
-			// -> synchronize copy to array
-			// -> loop over array
-			liArr = new GenericEventListener[li.size()];
-			liArr = li.toArray(liArr);
-		}
-		// -> avoid dead lock (see OLAT-3681)
-		//no sync during firing to listeners (potentially "long" taking - although recommendation is to keep event methods short.
-		
-		for (int i = 0; i < liArr.length; i++) {
-			try {
-				final GenericEventListener listener = liArr[i];
-				
-				//make sure GenericEvents are only sent when controller is not yet disposed
-				if (listener instanceof Controller) {
-					Controller dCtrl = (Controller)listener;
-					if (!dCtrl.isDisposed()) {
-						ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(new Runnable() {
-							public void run() {
-								listener.event(event);
-							}
-						}, UserActivityLoggerImpl.newLoggerForEventBus(dCtrl));
-					}
-				} else {
-					if(log.isDebug()){
-						log.debug("fireEvent: Non-Controller: "+listener);
-					}
-					//is there a need to differ the events sent on one VM and in cluster mode?
-					ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(new Runnable() {
-						public void run() {
-							listener.event(event);
-						}
-					}, ThreadLocalUserActivityLoggerInstaller.createEmptyUserActivityLogger());
-				}
-			} catch (RuntimeException e) {
-				log.error("Error while sending generic event: "+liArr[i], e);
-			}
-		}
-	}
-
-	/**
-	 * use only for administrative purposes!
-	 * @return a Set of IdentitieNames (Strings) who are registered with this event agency.
-	 */
-	Set<String> getListeningIdentityNames() {
-		synchronized (listeners) {//cluster_ok
-			Collection<String> c = listeners.values();
-			Set<String> distinctIds = new HashSet<String>(c);
-			return distinctIds;
-		}
-	}
-
-	/**
-	 * impl note: the underlying impl takes a weakHashMap, so unused entries are
-	 * cleared. an instance may not be added twice (make no sense anyway), since we
-	 * are using a map, not a list.
-	 * 
-	 * @param gel the instance which wants to listen to events.
-	 * @param identity the identity belonging to the listener, or null if there is
-	 *          none (e.g. the LockManager = the 'System')
-	 */
-	void addListener(GenericEventListener gel, Identity identity) {
-		synchronized (listeners) { //o_clusterOK by:fj
-			if (listeners.containsKey(gel)) {
-				//already registered, do nothing
-				return;
-			}
-			
-			String identityName = (identity != null? identity.getName() : null);
-			listeners.put(gel, identityName);
-		}
-	}
-
-	/**
-	 * @param gel
-	 */
-	void removeListener(GenericEventListener gel) {
-		synchronized (listeners) { //o_clusterOK by:fj
-			listeners.remove(gel);
-		}
-	}
-	
-	/**
-	 * 
-	 * @return the current number of listeners listening to this channel/eventagency 
-	 */
-	int getListenerCount() {
-		synchronized (listeners) { //o_clusterOK by:fj
-			return listeners.size();
-		}		
-	}
-
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/event/EventBus.java b/src/main/java/org/olat/core/util/event/EventBus.java
index 333e62c4f8f5945375ade2998bab4938838981b5..1ecbd476a195547a7cae46f6d4693a838ce4ce28 100644
--- a/src/main/java/org/olat/core/util/event/EventBus.java
+++ b/src/main/java/org/olat/core/util/event/EventBus.java
@@ -24,9 +24,6 @@
 */
 package org.olat.core.util.event;
 
-import java.util.Map;
-import java.util.Set;
-
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 
@@ -57,7 +54,7 @@ public interface EventBus {
 	 *          belongs, or null if that is not known or the olat-system itself.
 	 * @param ores the OLATResourceable
 	 */
-	public abstract void registerFor(GenericEventListener gel, Identity identity, OLATResourceable ores);
+	public void registerFor(GenericEventListener gel, Identity identity, OLATResourceable ores);
 
 	/**
 	 * deregisters/removes a GenericEventListener to listen to events concerning
@@ -66,7 +63,7 @@ public interface EventBus {
 	 * @param gel
 	 * @param ores
 	 */
-	public abstract void deregisterFor(GenericEventListener gel, OLATResourceable ores);
+	public void deregisterFor(GenericEventListener gel, OLATResourceable ores);
 
 	/**
 	 * fires an event to all listeners interested in events concerning this
@@ -77,26 +74,7 @@ public interface EventBus {
 	 *          server olat installations)
 	 * @param ores the OLATResourceable
 	 */
-	public abstract void fireEventToListenersOf(MultiUserEvent event, OLATResourceable ores);
-
-	/**
-	 * returns a Set of Identities which had at the very moment controllers which
-	 * were listening to the OLATResourceable ores. Useful to e.g. warn a
-	 * power-user which wants to delete a resource (e.g. a course) that there are
-	 * users using this resource right at this time. NOTE: please use only for
-	 * OLAT admin tools in order to protect the privacy of users. If you would
-	 * like to say "the resource you want to delete is currently used by 10
-	 * users", but not say which users, then please use method
-	 * getListeningIdentityCntFor(OLATResourceable ores)..
-	 * <br>
-	 * Note for cluster: this method returns only the names of listeners within one node/vm.
-	 * However, the cnt of listeners is broadcasted amongst cluster nodes - see getListeningIdentityCntFor(OLATResourceable ores);
-	 * 
-	 * @param ores the OLATResourceable
-	 * @return a Set of Identities which had at the very moment controllers which
-	 *         were listening to the OLATResourceable ores
-	 */
-	public abstract Set<String> getListeningIdentityNamesFor(OLATResourceable ores);
+	public void fireEventToListenersOf(MultiUserEvent event, OLATResourceable ores);
 
 	/**
 	 * 
@@ -104,15 +82,6 @@ public interface EventBus {
 	 * @param ores the resourceable
 	 * @return the number of people currently using this resource
 	 */
-	public abstract int getListeningIdentityCntFor(OLATResourceable ores);
-
-	/**
-	 * For admin purposes only! gets the whole infocenter and typeInfocenter map
-	 * (keys: String-form of OLATResoureable; values: EventAgencies) as a map.
-	 * 
-	 * @return the whole infocenter map
-	 */
-	public abstract Map<String, EventAgency> getUnmodifiableInfoCenter();
-
+	public int getListeningIdentityCntFor(OLATResourceable ores);
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/mail/MailManager.java b/src/main/java/org/olat/core/util/mail/MailManager.java
index d17ec705b84d51bde63b02a492be9bf0840c3a65..9a3edef8637dffef4a736a5cdc89c11513f4ec07 100644
--- a/src/main/java/org/olat/core/util/mail/MailManager.java
+++ b/src/main/java/org/olat/core/util/mail/MailManager.java
@@ -139,8 +139,6 @@ public interface MailManager {
 	 */
 	public MailerResult forwardToRealInbox(Identity identity, DBMail mail, MailerResult result);
 	
-	public boolean isHtmlEmail(String text);
-	
 	public String getMailTemplate();
 	
 	public void setMailTemplate(String template);
diff --git a/src/main/java/org/olat/core/util/mail/MailTemplate.java b/src/main/java/org/olat/core/util/mail/MailTemplate.java
index e65cbf45d6434b3ff69e6d8be482966a4068ad7a..a81b2757cfb3e8fc49d8d21cec8bc28d0a717602 100644
--- a/src/main/java/org/olat/core/util/mail/MailTemplate.java
+++ b/src/main/java/org/olat/core/util/mail/MailTemplate.java
@@ -129,7 +129,7 @@ public abstract class MailTemplate {
 	 * @param context The context where to put the variables
 	 * @param recipient The current identity which will get the email
 	 */
-	public abstract void putVariablesInMailContext(VelocityContext context, Identity recipient);
+	public abstract void putVariablesInMailContext(VelocityContext vContext, Identity recipient);
 	
 	public void addToContext(String name, String value) {
 		context.put(name, value);
diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
index 40305bda06ab46ab83b9918c93b6023303d62552..0bf659b01dfe9d80282ef800695bcadcbf1c1073 100644
--- a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
+++ b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
@@ -696,9 +696,9 @@ public class MailManagerImpl extends BasicManager implements MailManager {
 		MailContent content = bundle.getContent();
 
 		String template = getMailTemplate();
-		boolean htmlTemplate = isHtmlEmail(template);
+		boolean htmlTemplate = StringHelper.isHtml(template);
 		String body = content.getBody();
-		boolean htmlContent =  isHtmlEmail(body);
+		boolean htmlContent =  StringHelper.isHtml(body);
 		if(htmlTemplate && !htmlContent) {
 			body = body.replace("&", "&amp;");
 			body = body.replace("<", "&lt;");
@@ -1521,7 +1521,7 @@ public class MailManagerImpl extends BasicManager implements MailManager {
 				// with attachment use multipart message
 				Multipart multipart = new MimeMultipart("mixed");
 				// 1) add body part
-				if(isHtmlEmail(body)) {
+				if(StringHelper.isHtml(body)) {
 					Multipart alternativePart = createMultipartAlternative(body);
 					MimeBodyPart wrap = new MimeBodyPart();
 					wrap.setContent(alternativePart);
@@ -1551,7 +1551,7 @@ public class MailManagerImpl extends BasicManager implements MailManager {
 				msg.setContent(multipart);
 			} else {
 				// without attachment everything is easy, just set as text
-				if(isHtmlEmail(body)) {
+				if(StringHelper.isHtml(body)) {
 					msg.setContent(createMultipartAlternative(body));
 				} else {
 					msg.setText(body, "utf-8");
@@ -1589,17 +1589,6 @@ public class MailManagerImpl extends BasicManager implements MailManager {
 		multipart.addBodyPart(htmlPart);
 		return multipart;
 	}
-	
-	@Override
-	public boolean isHtmlEmail(String text) {
-		if(text.contains("<html") || text.contains("<body") || text.contains("<p") || text.contains("<span")) {
-			return true;
-		}
-		if(text.contains("<HTML") || text.contains("<BODY") || text.contains("<P") || text.contains("<SPAN")) {
-			return true;
-		}
-		return false;
-	}
 
 	@Override
 	public void sendMessage(MimeMessage msg, MailerResult result){
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailController.java b/src/main/java/org/olat/core/util/mail/ui/MailController.java
index 89db8b98a95f9f98cf6df0d65ddd67ab520c5201..c86f36386d82768808ab9c732c27b09edd889448 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailController.java
@@ -150,7 +150,7 @@ public class MailController extends FormBasicController {
 		String formattedBody;
 		if(!StringHelper.containsNonWhitespace(body)) {
 			formattedBody = "";
-		} else if(mailManager.isHtmlEmail(body)) {
+		} else if(StringHelper.isHtml(body)) {
 			//html -> don't replace
 			formattedBody = body;
 		} else {
diff --git a/src/main/java/org/olat/course/PersistingCourseImpl.java b/src/main/java/org/olat/course/PersistingCourseImpl.java
index 942e107b88db823c24f8d2685c2cb3fc7f7c92ce..1156d7db7fd556ddaa265af66b59d6e148204bc1 100644
--- a/src/main/java/org/olat/course/PersistingCourseImpl.java
+++ b/src/main/java/org/olat/course/PersistingCourseImpl.java
@@ -29,6 +29,7 @@ import java.io.File;
 import java.io.Serializable;
 
 import org.olat.admin.quota.QuotaConstants;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.IdentityEnvironment;
@@ -63,6 +64,7 @@ import org.olat.course.run.environment.CourseEnvironmentImpl;
 import org.olat.course.tree.CourseEditorTreeModel;
 import org.olat.course.tree.CourseEditorTreeNode;
 import org.olat.modules.glossary.GlossaryManager;
+import org.olat.modules.reminder.ReminderService;
 import org.olat.modules.sharedfolder.SharedFolderManager;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryImportExport;
@@ -375,6 +377,10 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 		//  pro increased transaction timeout: would fix OLAT-5368 but only move the problem
 		//@TODO OLAT-2597: real solution is a long-running background-task concept...
 		DBFactory.getInstance().intermediateCommit();
+		
+		//export reminders
+		CoreSpringFactory.getImpl(ReminderService.class)
+			.exportReminders(myRE, fExportedDataDir);
 
 		log.info("exportToFilesystem: exporting course "+this+" to "+exportDirectory+" done.");
 		log.info("finished export course '"+getCourseTitle()+"' in t="+Long.toString(System.currentTimeMillis()-s));
@@ -466,7 +472,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 			XStream xstream = CourseXStreamAliases.getReadCourseXStream();
 			return XStreamHelper.readObject(xstream, ((VFSLeaf)vfsItem).getInputStream());
 		} catch (Exception e) {
-			log.error("Cannot read course tree file: " + fileName);
+			log.error("Cannot read course tree file: " + fileName, e);
 			throw new CorruptedCourseException("Cannot resolve file: " + fileName + " course=" + toString(), e);
 		}
 	}
diff --git a/src/main/java/org/olat/course/assessment/AssessmentEditController.java b/src/main/java/org/olat/course/assessment/AssessmentEditController.java
index 9ac8de7219869dcb208d809565b1330685f15968..3b271e22542f9cb2788794d44334cf017c481578 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentEditController.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentEditController.java
@@ -101,7 +101,7 @@ public class AssessmentEditController extends BasicController {
 	 */
 	public AssessmentEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
 			ICourse course, AssessableCourseNode courseNode, AssessedIdentityWrapper assessedIdentityWrapper,
-			boolean showCourseNodeDetails, boolean saveAndCloseButton) {
+			boolean showCourseNodeDetails, boolean saveAndCloseButton, boolean showBackLink) {
 		super(ureq, wControl);
 		this.assessedIdentityWrapper = assessedIdentityWrapper;
 		this.courseNode = courseNode;
@@ -125,6 +125,7 @@ public class AssessmentEditController extends BasicController {
 			hideLogButton = LinkFactory.createButtonSmall("command.hidelog", detailView, this);
 			showLogButton = LinkFactory.createButtonSmall("command.showlog", detailView, this);
 			backLink = LinkFactory.createLinkBack(detailView, this);
+			backLink.setVisible(showBackLink);
 			
 			// Add the user object to the view
 			Identity assessedIdentity = assessedIdentityWrapper.getIdentity();
diff --git a/src/main/java/org/olat/course/assessment/AssessmentMainController.java b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
index 3abef2031e9cb0b5426ba220fd0135dfba008c61..7afc0a109fc6643ecda1b0b3179e594bd4d1cd9f 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentMainController.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
@@ -368,7 +368,8 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 			// select user
 			assessedIdentityWrapper = AssessmentHelper.wrapIdentity(focusOnIdentity, localUserCourseEnvironmentCache, initialLaunchDates, course, null);
 			
-			identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(), ureq, stackPanel, assessedIdentityWrapper.getIdentity(), course, true);
+			identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(), ureq, stackPanel,
+					assessedIdentityWrapper.getIdentity(), course, true, true, false);
 			listenTo(identityAssessmentController);
 			setContent(identityAssessmentController.getInitialComponent());
 		}
@@ -805,12 +806,14 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 	private void initIdentityEditController(UserRequest ureq, ICourse course) {
 		if (currentCourseNode == null) {
 			removeAsListenerAndDispose(identityAssessmentController);
-			identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(),ureq, stackPanel, assessedIdentityWrapper.getIdentity(), course, true);
+			identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(),ureq, stackPanel,
+					assessedIdentityWrapper.getIdentity(), course, true, true, false);
 			listenTo(identityAssessmentController);
 			setContent(identityAssessmentController.getInitialComponent());
 		} else {
 			removeAsListenerAndDispose(assessmentEditController);
-			assessmentEditController = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, currentCourseNode, assessedIdentityWrapper, true, false);
+			assessmentEditController = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, currentCourseNode,
+					assessedIdentityWrapper, true, false, true);
 			listenTo(assessmentEditController);
 			main.setContent(assessmentEditController.getInitialComponent());
 		}
diff --git a/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java b/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java
index 35ec4aedc568c2957db567998ce47607cbc45690..77f13d21e31e3adda73b9db7c503aa67663de5b5 100644
--- a/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java
+++ b/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java
@@ -71,7 +71,8 @@ import org.olat.course.run.userview.UserCourseEnvironment;
  */
 public class IdentityAssessmentEditController extends BasicController {
 	
-	private boolean mayEdit;
+	private final boolean mayEdit;
+	private final boolean pushToStackPanel;
 	private final VelocityContainer identityAssessmentVC;
 	private StackedPanel main;
 	private AssessmentEditController assessmentEditCtr;
@@ -91,20 +92,18 @@ public class IdentityAssessmentEditController extends BasicController {
 	 * @param assessedUserCourseEnvironment The assessed identitys user course environment
 	 * @param course
 	 * @param mayEdit true: user may edit the assessment, false: readonly view (user view)
-	 */
-	public IdentityAssessmentEditController(WindowControl wControl, UserRequest ureq, BreadcrumbPanel stackPanel,
-			Identity assessedIdentity, ICourse course, boolean mayEdit) {
-		this(wControl, ureq, stackPanel, assessedIdentity, course, mayEdit, true); 
-	}
-		
+	 * @param headers
+	 */	
 	public IdentityAssessmentEditController(WindowControl wControl, UserRequest ureq, BreadcrumbPanel stackPanel,
-			Identity assessedIdentity, ICourse course, boolean mayEdit, boolean headers) {
-
+			Identity assessedIdentity, ICourse course, boolean mayEdit, boolean headers, boolean pushToStackPanel) {
 		super(ureq, wControl);
-		this.stackPanel = stackPanel;
+		
 		this.mayEdit = mayEdit;
-		assessedUserCourseEnvironment = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
+		this.stackPanel = stackPanel;
 		this.ores = OresHelper.clone(course);
+		this.pushToStackPanel = pushToStackPanel;
+		
+		assessedUserCourseEnvironment = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
 
 		identityAssessmentVC = createVelocityContainer("identityassessment");
 		if(headers) {
@@ -193,9 +192,16 @@ public class IdentityAssessmentEditController extends BasicController {
 			UserCourseInformationsManager userCourseInformationsManager = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
 			Date initialLaunchDate = userCourseInformationsManager.getInitialLaunchDate(ores.getResourceableId(),  assessedUserCourseEnvironment.getIdentityEnvironment().getIdentity());
 			AssessedIdentityWrapper assessedIdentityWrapper = AssessmentHelper.wrapIdentity(assessedUserCourseEnvironment, initialLaunchDate, courseNode);
-			assessmentEditCtr = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, courseNode, assessedIdentityWrapper, true, false);			
+			assessmentEditCtr = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, courseNode,
+					assessedIdentityWrapper, true, false, !pushToStackPanel);			
 			listenTo(assessmentEditCtr);
-			main.setContent(assessmentEditCtr.getInitialComponent());
+			
+			if(stackPanel != null && pushToStackPanel) {
+				stackPanel.pushController(courseNode.getShortTitle(), assessmentEditCtr);
+			} else {
+				main.setContent(assessmentEditCtr.getInitialComponent());
+			}
+
 		} else {
 			throw new OLATSecurityException("doEditNodeAssessment() called but controller configured with mayEdit=false");
 		}
diff --git a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
index f63fcd4d776d41734b42f0774eb40706d06ba644..d158e3c2d3e9583c218b6868dbfafd67f3fe8716 100644
--- a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
+++ b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
@@ -266,7 +266,7 @@ public class BulkAssessmentOverviewController extends FormBasicController {
 
 		StepRunnerCallback finish = new StepRunnerCallback() {
 			@Override
-			public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
+			public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
 				Date scheduledDate = (Date)runContext.get("scheduledDate");
 				AssessableCourseNode courseNode = (AssessableCourseNode)runContext.get("courseNode");
 				BulkAssessmentDatas datas = (BulkAssessmentDatas)runContext.get("datas");
@@ -300,12 +300,12 @@ public class BulkAssessmentOverviewController extends FormBasicController {
 			Step start = new BulkAssessment_2_DatasStep(ureq, courseNode, datas, editableTask);
 			StepRunnerCallback finish = new StepRunnerCallback() {
 				@Override
-				public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
+				public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
 					Task task = (Task)runContext.get("task");
 					Date scheduledDate = (Date)runContext.get("scheduledDate");
-					AssessableCourseNode courseNode = (AssessableCourseNode)runContext.get("courseNode");
-					BulkAssessmentDatas datas = (BulkAssessmentDatas)runContext.get("datas");
-					Feedback feedback = doUpdateBulkAssessment(task, courseNode, scheduledDate, datas);
+					AssessableCourseNode assessableCourseNode = (AssessableCourseNode)runContext.get("courseNode");
+					BulkAssessmentDatas bulkDatas = (BulkAssessmentDatas)runContext.get("datas");
+					Feedback feedback = doUpdateBulkAssessment(task, assessableCourseNode, scheduledDate, bulkDatas);
 					runContext.put("feedback", feedback);
 					editedTask = null;
 					return StepsMainRunController.DONE_MODIFIED;
@@ -314,7 +314,7 @@ public class BulkAssessmentOverviewController extends FormBasicController {
 			
 			StepRunnerCallback cancel = new StepRunnerCallback() {
 				@Override
-				public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
+				public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
 					taskManager.returnTaskAfterEdition(editableTask, null);
 					editedTask = null;
 					return Step.NOSTEP;
diff --git a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentToolController.java b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentToolController.java
index a54021a1dc1c45387b6120af44dec3013fcc15cb..efd64c066766527a267b9b403a2b6869750b5bf2 100644
--- a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentToolController.java
+++ b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentToolController.java
@@ -103,7 +103,7 @@ public class BulkAssessmentToolController extends BasicController {
 	private void doOpen(UserRequest ureq) {
 		StepRunnerCallback finish = new StepRunnerCallback() {
 			@Override
-			public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
+			public Step execute(UserRequest uureq, WindowControl bwControl, StepsRunContext runContext) {
 				Date scheduledDate = (Date)runContext.get("scheduledDate");
 				BulkAssessmentDatas datas = (BulkAssessmentDatas)runContext.get("datas");
 				Feedback feedback = doBulkAssessment(scheduledDate, datas);
diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
index 49d14c41a12a5f60901cb4daf47e376c9697f147..1915514580fcb64c894aff4222aaa11e89896fd8 100644
--- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
+++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
@@ -4,8 +4,7 @@
 	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
   
-  <class name="org.olat.course.assessment.model.UserEfficiencyStatementImpl" table="o_as_eff_statement">	
-	<cache usage="transactional" />
+  <class name="org.olat.course.assessment.model.UserEfficiencyStatementImpl" table="o_as_eff_statement">
 
 	<id name="key" type="long" column="id"	unsaved-value="null">
 		<generator class="hilo"/>
@@ -44,8 +43,7 @@
                  cascade="none"/>
   </class>
   
-  <class name="org.olat.course.assessment.model.UserEfficiencyStatementStandalone" table="o_as_eff_statement">	
-	<cache usage="transactional" />
+  <class name="org.olat.course.assessment.model.UserEfficiencyStatementStandalone" table="o_as_eff_statement">
 
 	<id name="key" type="long" column="id"	unsaved-value="null">
 		<generator class="hilo"/>
diff --git a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties
index b825eec5d5498379b8fbe1df498bd9e453dd19b6..5a50ffa9f2b7fbac23b7b380fd28637424b7b748 100644
--- a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties
@@ -93,5 +93,5 @@ target.courseAndGroups=Teilnehmer aus Kurs und Gruppen
 target.groups=Nur Gruppenteilnehmer
 target.course=Nur Kursteilnehmer
 time.formatted={0}m
-warning.missing.element=Ein oder mehrere Kursbaustein in dem Konfiguration konnte im Kurs nicht gefunden werden.
+warning.missing.element=Ein oder mehrere konfigurierte Kursbausteine konnten im Kurs nicht gefunden werden. Bitte \u00FCberpr\u00FCfen Sie die Kursbausteineinschr\u00E4nkungen.
 warning.missing.start.element=Das Startbaustein konnte nicht gefunden werden.
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/condition/additionalconditions/AdditionalCondition.java b/src/main/java/org/olat/course/condition/additionalconditions/AdditionalCondition.java
index 5f47eb0b10fc4d9be16b53bf9d2290769fecc5d8..8081ccce4beec05f3ee52d5f98d016db9480d73f 100644
--- a/src/main/java/org/olat/course/condition/additionalconditions/AdditionalCondition.java
+++ b/src/main/java/org/olat/course/condition/additionalconditions/AdditionalCondition.java
@@ -33,7 +33,11 @@ public abstract class AdditionalCondition extends Condition implements Cloneable
 	
 	protected AbstractAccessableCourseNode node;
 	protected Long courseId;
+	
+	// The field answers must not be used, it's only there for XStream's compatibility purpose
+	@Deprecated
 	protected AdditionalConditionAnswerContainer answers;
+	
 	/**
 	 * 
 	 * @return the controller that is used to input the condition
@@ -46,8 +50,8 @@ public abstract class AdditionalCondition extends Condition implements Cloneable
 	 * @return NULL if something went wrong, true if the condition was met or false if it hadn't been fulfilled
 	 * 
 	 */
-	public abstract Boolean evaluate();
-	public abstract Boolean pwdEvaluate();
+	public abstract boolean evaluate(Object userObject);
+	
 	/**
 	 * used to get an optional controller if this additionalcondition could be fulfilled with userinteraction
 	 * @param ureq
@@ -56,24 +60,23 @@ public abstract class AdditionalCondition extends Condition implements Cloneable
 	 */
 	public abstract Controller getUserInputController(UserRequest ureq, WindowControl wControl);
 	
-	public String getNodeIdentifier(){
-		return node!=null?node.getIdent():null;
+	public String getNodeIdentifier() {
+		return node != null ? node.getIdent() : null;
 	}
 	
-	public Long getCourseId(){
+	public Long getCourseId() {
 		return courseId;
 	}
 	
-	public void setAnswers(AdditionalConditionAnswerContainer answers){
+	public void setAnswers(AdditionalConditionAnswerContainer answers) {
 		this.answers = answers;
 	}
 	
-	protected void setNode(AbstractAccessableCourseNode node){
+	protected void setNode(AbstractAccessableCourseNode node) {
 		this.node = node;
 	}
 	
-	protected void setCourseId(Long courseId){
+	protected void setCourseId(Long courseId) {
 		this.courseId = courseId;
 	}
-	
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/condition/additionalconditions/AdditionalConditionManager.java b/src/main/java/org/olat/course/condition/additionalconditions/AdditionalConditionManager.java
index cb9b8731cc97793d94045e294c18ecbb63b96556..0a4935d45aeeede2f62fb2e32854b83f7818f0d0 100644
--- a/src/main/java/org/olat/course/condition/additionalconditions/AdditionalConditionManager.java
+++ b/src/main/java/org/olat/course/condition/additionalconditions/AdditionalConditionManager.java
@@ -40,19 +40,17 @@ public class AdditionalConditionManager {
 	}
 	
 	public Boolean evaluateConditions(){
-		Boolean retVal = true;
-		for(AdditionalCondition cond : node.getAdditionalConditions()){
-			cond.setAnswers(answers);
+		boolean retVal = true;
+		for(AdditionalCondition cond : node.getAdditionalConditions()) {
 			cond.setNode(node);
 			cond.setCourseId(courseId);
-			retVal = cond.pwdEvaluate();
+			retVal = cond.evaluate(answers);
 			//otherwise all users on this node can enter the course if one user had known the correct answer 
-			cond.setAnswers(null);
-			if(retVal==null || !retVal){
+			if(!retVal) {
 				break;
 			}
 		}
-		return (retVal!=null?retVal:false);
+		return retVal;
 	}
 	
 	
@@ -64,15 +62,11 @@ public class AdditionalConditionManager {
 	 * @return null if either nothing is wrong or the user is unable to influence the condition in olat (and won't get a more detailed error-message) 
 	 */
 	public Controller nextUserInputController(UserRequest ureq, WindowControl wControl){
-		Boolean retVal;
 		for(AdditionalCondition cond : node.getAdditionalConditions()){
-			cond.setAnswers(answers);
 			cond.setNode(node);
 			cond.setCourseId(courseId);
-			
-			retVal = cond.evaluate();
-			
-			if(retVal != null && !retVal.booleanValue()){
+			boolean retVal = cond.evaluate(answers);
+			if(!retVal) {
 				Controller ctrl = cond.getUserInputController(ureq, wControl);
 				CourseNodeConfiguration config = CourseNodeFactory.getInstance().getCourseNodeConfiguration(node.getType());
 				return TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, node, config.getIconCSSClass());
diff --git a/src/main/java/org/olat/course/condition/additionalconditions/PasswordCondition.java b/src/main/java/org/olat/course/condition/additionalconditions/PasswordCondition.java
index cd2a7a279f8cf3a53c4003417ca3e609c4c13315..0e54b5d7293feb469be1bc2520a1b7197944e769 100644
--- a/src/main/java/org/olat/course/condition/additionalconditions/PasswordCondition.java
+++ b/src/main/java/org/olat/course/condition/additionalconditions/PasswordCondition.java
@@ -35,6 +35,9 @@ public class PasswordCondition extends AdditionalCondition {
 	
 	// <OLATCE-91>
 	private String password;
+	
+	// The field answer must not be used, it's only there for XStream's compatibility purpose
+	@SuppressWarnings("unused") @Deprecated
 	private String answer;
 	
 	public final static String PASSWORD_ENDING = "password";
@@ -46,26 +49,19 @@ public class PasswordCondition extends AdditionalCondition {
 
 	// <OLATCE-91>
 	@Override
-	public Boolean evaluate() {
-		boolean retVal = (password==null?true:password.equals(answer)); 
-		answer=null;
-		return retVal;
-	}
-	
-	public Boolean pwdEvaluate() {
-		PasswordStore store = null;
-		
-		if(answers != null) {
-			Object obj = answers.getAnswers(node.getIdent(), courseId.toString()); 
+	public boolean evaluate(Object userAnswerObj) {
+		String userAnswer = null;
+		if(userAnswerObj instanceof AdditionalConditionAnswerContainer) {
+			AdditionalConditionAnswerContainer answersContainer = (AdditionalConditionAnswerContainer)userAnswerObj;
+			Object obj = answersContainer.getAnswers(node.getIdent(), courseId.toString()); 
 			if(obj instanceof PasswordStore){
-				store = (PasswordStore) obj;
+				userAnswer = ((PasswordStore)obj).getPassword();
 			}
+		} else if(userAnswerObj instanceof String) {
+			userAnswer = (String)userAnswerObj;
 		}
-		
-		if(store !=null) {
-			answer = store.getPassword();
-		}
-		return evaluate();
+
+		return password==null ? true : password.equals(userAnswer); 
 	}
 
 	@Override
@@ -85,7 +81,8 @@ public class PasswordCondition extends AdditionalCondition {
 	public void setPassword(String password){
 		this.password = password;
 	}
-
+	
+	@Deprecated
 	public void setAnswer(String answer) {
 		this.answer = answer;
 	}
diff --git a/src/main/java/org/olat/course/condition/additionalconditions/PasswordVerificationController.java b/src/main/java/org/olat/course/condition/additionalconditions/PasswordVerificationController.java
index 1368cac4b1a9804eccbeaff5dae5b6b3b509eb3c..0ce78f44d06199bc02bea8cbfe740369abe58744 100644
--- a/src/main/java/org/olat/course/condition/additionalconditions/PasswordVerificationController.java
+++ b/src/main/java/org/olat/course/condition/additionalconditions/PasswordVerificationController.java
@@ -81,13 +81,12 @@ public class PasswordVerificationController extends FormBasicController {
 		if(!StringHelper.containsNonWhitespace(pwElement.getValue())) {
 			pwElement.setErrorKey("form.legende.mandatory", new String[] {});
 		} else {
-			condition.setAnswer(pwElement.getValue());
-			valid = condition.evaluate();
-			if (!valid) {
-				pwElement.setErrorKey("password.incorrect", new String[] {});
-			} else {
+			valid = condition.evaluate(pwElement.getValue());
+			if (valid) {
 				CourseNodePasswordManager cnpm = CourseNodePasswordManagerImpl.getInstance();
 				cnpm.updatePwd(ureq.getIdentity(), condition.getNodeIdentifier(), condition.getCourseId().toString(), pwElement.getValue());
+			} else {
+				pwElement.setErrorKey("password.incorrect", new String[0]);
 			}
 		}
 		
diff --git a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
index 4b2a59f6c1ccdfb93ab373e7b02032b54d7c122d..aaf5bb3cac635d88192a910f1c655afc66c4f332 100644
--- a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
@@ -356,7 +356,7 @@ coursefolder.close=Ablageordner schliessen
 coursefolder.name=Ablageordner
 coursestatus.ok.message=Dieser Kurs enth\u00E4lt keine Fehler im Editor.
 deletenode.confirm=Sind Sie sicher, dass Sie diesen Kursbaustein und alle seine untergeordneten Kursbausteine permanent l\u00F6schen wollen?
-deletenode.confirm.inuse.assessment.mode=$\:deletenode.confirm <div class='o_warning'>Diese Kursbaustein wird gerade von einem Prüfungskonfiguration benutzt.</div>
+deletenode.confirm.inuse.assessment.mode=$\:deletenode.confirm <div class='o_warning'>Dieser Kursbaustein wird in mindestens einer Pr\u00FCfungskonfiguration benutzt.</div>
 deletenode.error.rootnode=Der Hauptkursbaustein kann nicht gel\u00F6scht werden.
 deletenode.error.selectfirst=Bitte w\u00E4hlen Sie zun\u00E4chst einen Kursbaustein Ihres Kurses.
 deletenode.header=Kursbaustein {0} l\u00F6schen
diff --git a/src/main/java/org/olat/course/member/MemberListController.java b/src/main/java/org/olat/course/member/MemberListController.java
index 208ad1eb05bb002e340c4f45409b9f239c9b5e65..7226d139f1bafec31965f802326402eff2782e1f 100644
--- a/src/main/java/org/olat/course/member/MemberListController.java
+++ b/src/main/java/org/olat/course/member/MemberListController.java
@@ -20,9 +20,15 @@
 package org.olat.course.member;
 
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.IdentityAssessmentEditController;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberView;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -31,19 +37,36 @@ import org.olat.repository.RepositoryEntry;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public class MemberListController extends AbstractMemberListController {
+
+	private IdentityAssessmentEditController identityAssessmentController;
 	
 	private final SearchMembersParams searchParams;
 	
-	public MemberListController(UserRequest ureq, WindowControl wControl,
+	public MemberListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			RepositoryEntry repoEntry, SearchMembersParams searchParams, String infos) {
-		super(ureq, wControl, repoEntry, "all_member_list");
+		super(ureq, wControl, repoEntry, "all_member_list", stackPanel);
 		this.searchParams = searchParams;
 		
 		if(StringHelper.containsNonWhitespace(infos)) {
-			mainVC.contextPut("infos", infos);
+			flc.contextPut("infos", infos);
 		}
 	}
 
+	@Override
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+		removeAsListenerAndDispose(identityAssessmentController);
+		
+		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+		ICourse course = CourseFactory.loadCourse(repoEntry.getOlatResource());
+		
+		identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(),ureq, toolbarPanel,
+				assessedIdentity, course, true, false, true);
+		listenTo(identityAssessmentController);
+		
+		String displayName = userManager.getUserDisplayName(assessedIdentity);
+		toolbarPanel.pushController(displayName, identityAssessmentController);
+	}
+
 	@Override
 	public SearchMembersParams getSearchParams() {
 		return searchParams;
diff --git a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
index 2c471565a218c9d8df4f03987719cd1b33ae79a5..092fd7925b35389eb1b06ff90700bc91e7154fb8 100644
--- a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
+++ b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
@@ -20,11 +20,20 @@
 package org.olat.course.member;
 
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.IdentityAssessmentEditController;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberView;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -34,38 +43,73 @@ import org.olat.repository.RepositoryEntry;
  */
 public class MemberListWithOriginFilterController extends AbstractMemberListController {
 	
+	private static final  String[] originKeys = new String[]{"all", "repo", "group"};
+	
+	private SingleSelection originEl;
+	
+	private IdentityAssessmentEditController identityAssessmentController;
+	
 	private final SearchMembersParams searchParams;
-	private final OriginFilterController filterController;
 	
-	public MemberListWithOriginFilterController(UserRequest ureq, WindowControl wControl,
+	public MemberListWithOriginFilterController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
 			RepositoryEntry repoEntry, SearchMembersParams searchParams, String infos) {
-		super(ureq, wControl, repoEntry, "member_list_origin_filter");
+		super(ureq, wControl, repoEntry, "member_list_origin_filter", toolbarPanel);
 		this.searchParams = searchParams;
 		
-		filterController = new OriginFilterController(ureq, wControl);
-		listenTo(filterController);
-		mainVC.put("originFilter", filterController.getInitialComponent());
-		
 		if(StringHelper.containsNonWhitespace(infos)) {
-			mainVC.contextPut("infos", infos);
+			flc.contextPut("infos", infos);
 		}
 	}
 
 	@Override
-	public SearchMembersParams getSearchParams() {
-		return searchParams;
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		super.initForm(formLayout, listener, ureq);
+		
+		String[] openValues = new String[originKeys.length];
+		for(int i=originKeys.length; i-->0; ) {
+			openValues[i] = translate("search." + originKeys[i]);
+		}
+		originEl = uifactory.addRadiosHorizontal("originFilter", "search.origin.alt", formLayout, originKeys, openValues);
+		originEl.select("all", true);
+		originEl.addActionListener(FormEvent.ONCHANGE);
 	}
 
 	@Override
-	protected void event(UserRequest ureq, Controller source, Event event) {
-		if(source == filterController) {
-			if(event instanceof SearchOriginParams) {
-				SearchOriginParams filter = (SearchOriginParams)event;
-				searchParams.setRepoOrigin(filter.isRepoOrigin());
-				searchParams.setGroupOrigin(filter.isGroupOrigin());
-				reloadModel();
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(originEl == source) {
+			if(!originEl.isOneSelected() || originEl.isSelected(0)) {
+				searchParams.setRepoOrigin(true);
+				searchParams.setGroupOrigin(true);
+			} else if(originEl.isSelected(1)) {
+				searchParams.setRepoOrigin(true);
+				searchParams.setGroupOrigin(false);
+			} else if(originEl.isSelected(2)) {
+				searchParams.setRepoOrigin(false);
+				searchParams.setGroupOrigin(true);
 			}
+			reloadModel();
+		} else {
+			super.formInnerEvent(ureq, source, event);
 		}
-		super.event(ureq, source, event);
+	}
+	
+	@Override
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+		removeAsListenerAndDispose(identityAssessmentController);
+		
+		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+		ICourse course = CourseFactory.loadCourse(repoEntry.getOlatResource());
+		
+		identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(),ureq, toolbarPanel,
+				assessedIdentity, course, true, false, true);
+		listenTo(identityAssessmentController);
+		
+		String displayName = userManager.getUserDisplayName(assessedIdentity);
+		toolbarPanel.pushController(displayName, identityAssessmentController);
+	}
+
+	@Override
+	public SearchMembersParams getSearchParams() {
+		return searchParams;
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/MemberSearchController.java b/src/main/java/org/olat/course/member/MemberSearchController.java
index 43951776a3196fe86ba9d244ebd8c31dadcf9d9e..59308eb7c189363525ea459cc4b71af1c63060da 100644
--- a/src/main/java/org/olat/course/member/MemberSearchController.java
+++ b/src/main/java/org/olat/course/member/MemberSearchController.java
@@ -20,10 +20,17 @@
 package org.olat.course.member;
 
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.IdentityAssessmentEditController;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberView;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -34,16 +41,25 @@ import org.olat.repository.RepositoryEntry;
 public class MemberSearchController extends AbstractMemberListController {
 	
 	private SearchMembersParams searchParams = new SearchMembersParams();
-	private final MemberSearchForm searchForm;
 	
-	public MemberSearchController(UserRequest ureq, WindowControl wControl,
+	private MemberSearchForm searchForm;
+	private IdentityAssessmentEditController identityAssessmentController;
+	
+	public MemberSearchController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
 			RepositoryEntry repoEntry) {
-		super(ureq, wControl, repoEntry, "search_member_list");
+		super(ureq, wControl, repoEntry, "all_member_list", toolbarPanel);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		super.initForm(formLayout, listener, ureq);
 		
-		searchForm = new MemberSearchForm(ureq, wControl);
+		searchForm = new MemberSearchForm(ureq, getWindowControl(), mainForm);
+		searchForm.setEnabled(true);
 		listenTo(searchForm);
-		
-		mainVC.put("searchForm", searchForm.getInitialComponent());
+		membersTable.setSearchEnabled(true);
+		membersTable.setExtendedSearch(searchForm);
+		membersTable.expandExtendedSearch(ureq);
 	}
 
 	@Override
@@ -61,4 +77,19 @@ public class MemberSearchController extends AbstractMemberListController {
 		}
 		super.event(ureq, source, event);
 	}
+	
+	@Override
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+		removeAsListenerAndDispose(identityAssessmentController);
+		
+		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+		ICourse course = CourseFactory.loadCourse(repoEntry.getOlatResource());
+		
+		identityAssessmentController = new IdentityAssessmentEditController(getWindowControl(),ureq, toolbarPanel,
+				assessedIdentity, course, true, false, true);
+		listenTo(identityAssessmentController);
+		
+		String displayName = userManager.getUserDisplayName(assessedIdentity);
+		toolbarPanel.pushController(displayName, identityAssessmentController);
+	}
 }
diff --git a/src/main/java/org/olat/course/member/MemberSearchForm.java b/src/main/java/org/olat/course/member/MemberSearchForm.java
index 902ba545899f1251fecb1b248f72e5cef202dafb..4742da57dab868c4d755b22b1ab224692f3d1a47 100644
--- a/src/main/java/org/olat/course/member/MemberSearchForm.java
+++ b/src/main/java/org/olat/course/member/MemberSearchForm.java
@@ -20,19 +20,24 @@
 package org.olat.course.member;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.ExtendedFlexiTableSearchController;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
@@ -41,12 +46,13 @@ import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.EmailProperty;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MemberSearchForm extends FormBasicController {
+public class MemberSearchForm extends FormBasicController implements ExtendedFlexiTableSearchController {
 	
 	private String[] roleKeys = {"owner", "tutor", "attendee", "waiting"};
 	private String[] originKeys = new String[]{"all", "repo", "group"};
@@ -54,17 +60,19 @@ public class MemberSearchForm extends FormBasicController {
 	private TextElement login;
 	private SingleSelection originEl;
 	private MultipleSelectionElement rolesEl;
+	private FormLink searchButton;
 	
 	private Map<String,FormItem> propFormItems;
 	private List<UserPropertyHandler> userPropertyHandlers;
-	
-	private final UserManager userManager;
 
-	public MemberSearchForm(UserRequest ureq, WindowControl wControl) {
-		super(ureq, wControl, "search_form", Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale()));
-		
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
+	private boolean enabled = true;
+	
+	@Autowired
+	private UserManager userManager;
 
+	public MemberSearchForm(UserRequest ureq, WindowControl wControl, Form rootForm) {
+		super(ureq, wControl, LAYOUT_CUSTOM, "search_form", rootForm);
+		setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), getTranslator()));
 		initForm(ureq);
 	}
 
@@ -121,7 +129,8 @@ public class MemberSearchForm extends FormBasicController {
 
 		FormLayoutContainer buttonLayout = FormLayoutContainer.createDefaultFormLayout("button_layout", getTranslator());
 		formLayout.add(buttonLayout);
-		uifactory.addFormSubmitButton("search", "search", buttonLayout);
+		searchButton = uifactory.addFormLink("search", buttonLayout, Link.BUTTON);
+		searchButton.setCustomEnabledLinkCSS("btn btn-primary");
 	}
 	
 	@Override
@@ -129,8 +138,33 @@ public class MemberSearchForm extends FormBasicController {
 		//
 	}
 
+	@Override
+	public void setEnabled(boolean enable) {
+		this.enabled = enable;
+	}
+
+	@Override
+	public List<String> getConditionalQueries() {
+		return Collections.emptyList();
+	}
+
 	@Override
 	protected void formOK(UserRequest ureq) {
+		if(enabled) {
+			fireSearchEvent(ureq);
+		}
+	}
+	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(enabled) {
+			if (source == searchButton) {
+				fireSearchEvent(ureq);
+			}
+		}
+	}
+
+	private void fireSearchEvent(UserRequest ureq) {
 		SearchMembersParams params = new SearchMembersParams();
 		//roles
 		Collection<String> selectedKeys = rolesEl.getSelectedKeys();
diff --git a/src/main/java/org/olat/course/member/MembersManagementMainController.java b/src/main/java/org/olat/course/member/MembersManagementMainController.java
index 40ebedbf66f37eae1719c7ff6ec9997b6b76b4a8..291998ea7a1f7c66b0eafc559a9c9db0bb2413e1 100644
--- a/src/main/java/org/olat/course/member/MembersManagementMainController.java
+++ b/src/main/java/org/olat/course/member/MembersManagementMainController.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.tree.GenericTreeModel;
 import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.gui.components.tree.MenuTree;
@@ -70,6 +71,7 @@ public class MembersManagementMainController extends MainLayoutBasicController
 
 	private final MenuTree menuTree;
 	private final VelocityContainer mainVC;
+	private final TooledStackedPanel toolbarPanel;
 	private final LayoutMain3ColsController columnLayoutCtr;
 
 	private OrdersAdminController ordersController;
@@ -85,9 +87,10 @@ public class MembersManagementMainController extends MainLayoutBasicController
 	@Autowired
 	private AccessControlModule acModule;
 
-	public MembersManagementMainController(UserRequest ureq, WindowControl wControl, RepositoryEntry re) {
+	public MembersManagementMainController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel, RepositoryEntry re) {
 		super(ureq, wControl);
 		this.repoEntry = re;
+		this.toolbarPanel = toolbarPanel;
 
 		//logging
 		getUserActivityLogger().setStickyActionType(ActionType.admin);
@@ -192,7 +195,7 @@ public class MembersManagementMainController extends MainLayoutBasicController
 		Controller selectedCtrl = null;
 		if(CMD_MEMBERS.equals(cmd)) {
 			if(membersOverviewCtrl == null) {
-				membersOverviewCtrl = new MembersOverviewController(ureq, bwControl, repoEntry);
+				membersOverviewCtrl = new MembersOverviewController(ureq, bwControl, toolbarPanel, repoEntry);
 				listenTo(membersOverviewCtrl);
 			} else if(membersDirty) {
 				membersOverviewCtrl.reloadMembers();
diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java
index 3e52d2e090d12fb51914c6bb46960c5a3f115afb..c591f963693ca733a2f14c5626c3ae006b83b906 100644
--- a/src/main/java/org/olat/course/member/MembersOverviewController.java
+++ b/src/main/java/org/olat/course/member/MembersOverviewController.java
@@ -21,7 +21,6 @@ package org.olat.course.member;
 
 import java.util.List;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -30,6 +29,7 @@ import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
 import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
 import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -65,6 +65,7 @@ import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.model.RepositoryEntryPermissionChangeEvent;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -84,6 +85,7 @@ public class MembersOverviewController extends BasicController implements Activa
 	private final Link allMembersLink, ownersLink, tutorsLink, participantsLink, waitingListLink, searchLink;
 	private final SegmentViewComponent segmentView;
 	private final VelocityContainer mainVC;
+	private final TooledStackedPanel toolbarPanel;
 	
 	private AbstractMemberListController allMemberListCtrl;
 	private AbstractMemberListController ownersCtrl;
@@ -99,15 +101,16 @@ public class MembersOverviewController extends BasicController implements Activa
 	private DedupMembersConfirmationController dedupCtrl;
 	
 	private final RepositoryEntry repoEntry;
-	private final RepositoryManager repositoryManager;
-	private final BusinessGroupService businessGroupService;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
+	private BusinessGroupService businessGroupService;
 	
-	public MembersOverviewController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry) {
+	public MembersOverviewController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel, RepositoryEntry repoEntry) {
 		super(ureq, wControl);
 		this.repoEntry = repoEntry;
-		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
-		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-
+		this.toolbarPanel = toolbarPanel;
+		
 		mainVC = createVelocityContainer("members_overview");
 		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
 		
@@ -365,7 +368,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(true, true, true, true, true, false, true);
-			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, null);
+			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, searchParams, null);
 			listenTo(allMemberListCtrl);
 		}
 		
@@ -382,7 +385,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(true, false, false, false, false, false, false);
 			String infos = translate("owners.infos");
-			ownersCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams, infos);
+			ownersCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, searchParams, infos);
 			listenTo(ownersCtrl);
 		}
 		
@@ -399,7 +402,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, true, false, true, false, false, false);
 			String infos = translate("tutors.infos");
-			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, infos);
+			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, searchParams, infos);
 			listenTo(tutorsCtrl);
 		}
 		
@@ -416,7 +419,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, false, true, false, true, false, true);
 			String infos = translate("participants.infos");
-			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, infos);
+			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, searchParams, infos);
 			listenTo(participantsCtrl);
 		}
 		
@@ -433,7 +436,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, false, false, false, false, true, false);
 			String infos = translate("waiting.infos");
-			waitingCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams, infos);
+			waitingCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, searchParams, infos);
 			listenTo(waitingCtrl);
 		}
 		
@@ -448,7 +451,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_SEARCH_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			searchCtrl = new MemberSearchController(ureq, bwControl, repoEntry);
+			searchCtrl = new MemberSearchController(ureq, bwControl, toolbarPanel, repoEntry);
 			listenTo(searchCtrl);
 		}
 	
diff --git a/src/main/java/org/olat/course/member/_content/all_member_list.html b/src/main/java/org/olat/course/member/_content/all_member_list.html
index ecbac69a75c3612f7fd2ae3bc4216bda7a0e7249..b5d935a6a4eb1ea86f156fcce08f58b0f45de0ce 100644
--- a/src/main/java/org/olat/course/member/_content/all_member_list.html
+++ b/src/main/java/org/olat/course/member/_content/all_member_list.html
@@ -1,10 +1,15 @@
 #if($infos)
-	<br/>
-	<div class="clearfix">
-		<p class="o_info">$infos</p>
-	</div>
+	<div class="o_info">$infos</div>
 #end
-
-<div class="clearfix">
-	$r.render("memberList")
+<div class="o_block">$r.render("memberList")</div>
+<div class="o_button_group">
+	#if($r.available("edit.members"))
+		$r.render("edit.members")
+	#end
+	#if($r.available("table.header.mail"))
+		$r.render("table.header.mail")
+	#end
+	#if($r.available("table.header.remove"))
+		$r.render("table.header.remove")
+	#end
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html b/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html
index 00460bb1dc122770df34c5986bdf56a03572874e..3537dde3f9f55d6f9ed27f096c0b55a9ab35a5af 100644
--- a/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html
+++ b/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html
@@ -1,11 +1,18 @@
 #if($infos)
-	<div class="o_block clearfix">
-		<p class="o_info">$infos</p>
-	</div>
+	<div class="o_info ">$infos</div>
 #end
-<div class="clearfix" style="position:relative;">
-	<div class="o_button_group o_button_group_right">
-		$r.render("originFilter")
-	</div>
-	$r.render("memberList")
+<div class="o_button_group o_button_group_right">
+	$r.render("originFilter")
+</div>
+$r.render("memberList")
+<div class="o_button_group">
+	#if($r.available("edit.members"))
+		$r.render("edit.members")
+	#end
+	#if($r.available("table.header.mail"))
+		$r.render("table.header.mail")
+	#end
+	#if($r.available("table.header.remove"))
+		$r.render("table.header.remove")
+	#end
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/search_member_list.html b/src/main/java/org/olat/course/member/_content/search_member_list.html
index dec88523032d5707e21dfd436737ec210b9212f0..5f4163056c54ad0def245f56e00094448fb014b6 100644
--- a/src/main/java/org/olat/course/member/_content/search_member_list.html
+++ b/src/main/java/org/olat/course/member/_content/search_member_list.html
@@ -1,4 +1,4 @@
-$r.render("searchForm")
+
 <div class="clearfix">
 	$r.render("memberList")
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/ENCourseNode.java b/src/main/java/org/olat/course/nodes/ENCourseNode.java
index 36429598d879ed2ad6bebdc71c6db980127ad0f3..014e45d239b28534982926dc0170400f1fdb9c05 100644
--- a/src/main/java/org/olat/course/nodes/ENCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ENCourseNode.java
@@ -38,6 +38,7 @@ import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Roles;
 import org.olat.core.util.Util;
+import org.olat.core.util.filter.FilterFactory;
 import org.olat.course.ICourse;
 import org.olat.course.condition.ConditionEditController;
 import org.olat.course.editor.CourseEditorEnv;
@@ -191,13 +192,15 @@ public class ENCourseNode extends AbstractAccessableCourseNode {
 		/*
 		 * check group and area names for existence
 		 */
+		String nodeId = getIdent();
+		
 		ModuleConfiguration mc = getModuleConfiguration();
 		String areaStr = (String) mc.get(CONFIG_AREANAME);
-		String nodeId = getIdent();
 		if (areaStr != null) {
 			String[] areas = areaStr.split(",");
 			for (int i = 0; i < areas.length; i++) {
-				String trimmed = areas[i] != null ? areas[i].trim() : areas[i];
+				String trimmed = areas[i] != null ?
+						FilterFactory.getHtmlTagsFilter().filter(areas[i]).trim() : areas[i];
 				if (!trimmed.equals("") && !cev.existsArea(trimmed)) {
 					StatusDescription sd = new StatusDescription(StatusDescription.WARNING, "error.notfound.name", "solution.checkgroupmanagement",
 							new String[] { "NONE", trimmed }, translatorStr);
@@ -210,7 +213,8 @@ public class ENCourseNode extends AbstractAccessableCourseNode {
 		if (groupStr != null) {
 			String[] groups = groupStr.split(",");
 			for (int i = 0; i < groups.length; i++) {
-				String trimmed = groups[i] != null ? groups[i].trim() : groups[i];
+				String trimmed = groups[i] != null ?
+						FilterFactory.getHtmlTagsFilter().filter(groups[i]).trim() : groups[i];
 				if (!trimmed.equals("") && !cev.existsGroup(trimmed)) {
 					StatusDescription sd = new StatusDescription(StatusDescription.WARNING, "error.notfound.name", "solution.checkgroupmanagement",
 							new String[] { "NONE", trimmed }, translatorStr);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java
index 125a4e032f58dd2ccbe01dacdbd2591297083b5a..9dda96d3e843b9c7ae62d9bed34288555f828cc7 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java
@@ -161,7 +161,8 @@ public class AssessedIdentityOverviewController extends BasicController {
 			ICourse course = CourseFactory.loadCourse(courseOres);
 			UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
 			AssessedIdentityWrapper idWrapper = AssessmentHelper.wrapIdentity(uce, null, courseNode);
-			assessmentCtrl = new AssessmentEditController(ureq, getWindowControl(), null, course, courseNode, idWrapper, false, true);
+			assessmentCtrl = new AssessmentEditController(ureq, getWindowControl(), null, course, courseNode,
+					idWrapper, false, true, true);
 			assessmentCtrl.setIdentityInfos(false);
 			assessmentCtrl.setCourseNodeInfos(false);
 			assessmentCtrl.setTitleInfos(false);
diff --git a/src/main/java/org/olat/course/nodes/en/ENEditGroupAreaFormController.java b/src/main/java/org/olat/course/nodes/en/ENEditGroupAreaFormController.java
index b0d4ee6be242c5e2d13d79d88911bbc95a7156cd..2afb01b980cf03524c7fbe2ab15499a117116dd5 100644
--- a/src/main/java/org/olat/course/nodes/en/ENEditGroupAreaFormController.java
+++ b/src/main/java/org/olat/course/nodes/en/ENEditGroupAreaFormController.java
@@ -25,7 +25,6 @@
 package org.olat.course.nodes.en;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -158,21 +157,15 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 	@Override
 	protected void formOK(UserRequest ureq) {
 		// 1. group names
-		List<Long> groupKeys = getKeys(easyGroupList);
-		String groupName = "";
-		if (StringHelper.containsNonWhitespace(easyGroupList.getValue())){
-			groupName = easyGroupList.getValue();
-		}
-		moduleConfig.set(ENCourseNode.CONFIG_GROUPNAME, groupName);
-		moduleConfig.set(ENCourseNode.CONFIG_GROUP_IDS, groupKeys);
+		KeysAndNames groupKeysAndNames = (KeysAndNames)easyGroupList.getUserObject();
+		String groupNames = StringHelper.formatAsSortUniqCSVString(groupKeysAndNames.getNames());
+		moduleConfig.set(ENCourseNode.CONFIG_GROUPNAME, groupNames);
+		moduleConfig.set(ENCourseNode.CONFIG_GROUP_IDS, groupKeysAndNames.getKeys());
 		// 2. area names
-		List<Long> areaKeys = getKeys(easyAreaList);
-		String areaName = "";
-		if (StringHelper.containsNonWhitespace(easyAreaList.getValue())){
-			areaName = easyAreaList.getValue();
-		}
-		moduleConfig.set(ENCourseNode.CONFIG_AREANAME, areaName);
-		moduleConfig.set(ENCourseNode.CONFIG_AREA_IDS, areaKeys);
+		KeysAndNames areaKeysAndNames = (KeysAndNames)easyAreaList.getUserObject();
+		String areaNames = StringHelper.formatAsSortUniqCSVString(areaKeysAndNames.getNames());
+		moduleConfig.set(ENCourseNode.CONFIG_AREANAME, areaNames);
+		moduleConfig.set(ENCourseNode.CONFIG_AREA_IDS, areaKeysAndNames.getKeys());
 		// 3. cancel-enroll-enabled flag
 		Boolean cancelEnrollEnabled = enableCancelEnroll.getSelectedKeys().size()==1;
 		moduleConfig.set(ENCourseNode.CONF_CANCEL_ENROLL_ENABLED, cancelEnrollEnabled);
@@ -192,26 +185,22 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		// groups
-
-		String groupInitVal;
-		@SuppressWarnings("unchecked")
-		List<Long> groupKeys = (List<Long>)moduleConfig.get(ENCourseNode.CONFIG_GROUP_IDS);
+		List<Long> groupKeys = moduleConfig.getList(ENCourseNode.CONFIG_GROUP_IDS, Long.class);
 		if(groupKeys == null) {
-			groupInitVal = (String) moduleConfig.get(ENCourseNode.CONFIG_GROUPNAME);
-			if(StringHelper.containsNonWhitespace(groupInitVal)) {
-				groupKeys = businessGroupService.toGroupKeys(groupInitVal, cev.getCourseGroupManager().getCourseEntry());
+			String groupNames = (String) moduleConfig.get(ENCourseNode.CONFIG_GROUPNAME);
+			if(StringHelper.containsNonWhitespace(groupNames)) {
+				groupKeys = businessGroupService.toGroupKeys(groupNames, cev.getCourseGroupManager().getCourseEntry());
 			} else {
 				groupKeys = new ArrayList<Long>();
 			}
 		}
-		groupInitVal = getGroupNames(groupKeys);
-		
+		KeysAndNames groupInitVal = getGroupKeysAndNames(groupKeys);
 		chooseGroupsLink = uifactory.addFormLink("chooseGroup", formLayout, "btn btn-default o_xsmall o_form_groupchooser");
 		chooseGroupsLink.setLabel("form.groupnames", null);
 		chooseGroupsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_group");
 		
-		easyGroupList = uifactory.addStaticTextElement("group", null, groupInitVal == null ? "" : groupInitVal, formLayout);
-		easyGroupList.setUserObject(groupKeys);
+		easyGroupList = uifactory.addStaticTextElement("group", null, groupInitVal.getDecoratedNames(), formLayout);
+		easyGroupList.setUserObject(groupInitVal);
 		easyGroupList.setElementCssClass("text-muted");
 		
 		hasGroups = businessGroupService.countBusinessGroups(null, cev.getCourseGroupManager().getCourseEntry()) > 0;
@@ -222,21 +211,21 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 		}
 		
 		// areas
-		String areaInitVal;
+
 		@SuppressWarnings("unchecked")
 		List<Long> areaKeys = (List<Long>)moduleConfig.get(ENCourseNode.CONFIG_AREA_IDS);
 		if(areaKeys == null) {
-			areaInitVal = (String) moduleConfig.get(ENCourseNode.CONFIG_AREANAME);
-			areaKeys = areaManager.toAreaKeys(areaInitVal, cev.getCourseGroupManager().getCourseResource());
+			String areaNames = (String) moduleConfig.get(ENCourseNode.CONFIG_AREANAME);
+			areaKeys = areaManager.toAreaKeys(areaNames, cev.getCourseGroupManager().getCourseResource());
 		}
-		areaInitVal = getAreaNames(areaKeys);
 		
+		KeysAndNames areaInitVal = getAreaKeysAndNames(areaKeys);
 		chooseAreasLink = uifactory.addFormLink("chooseArea", formLayout, "btn btn-default o_xsmall o_form_areachooser");
 		chooseAreasLink.setLabel("form.areanames", null);
 		chooseAreasLink.setIconLeftCSS("o_icon o_icon-fw o_icon_courseareas");
 		
-		easyAreaList = uifactory.addStaticTextElement("area", null, areaInitVal == null ? "" : areaInitVal, formLayout);
-		easyAreaList.setUserObject(areaKeys);
+		easyAreaList = uifactory.addStaticTextElement("area", null, areaInitVal.getDecoratedNames(), formLayout);
+		easyAreaList.setUserObject(areaInitVal);
 		easyAreaList.setElementCssClass("text-muted");
 		
 		hasAreas = areaManager.countBGAreasInContext(cev.getCourseGroupManager().getCourseResource()) > 0;
@@ -493,14 +482,9 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 		if (source == groupChooseC) {
 			if (event == Event.DONE_EVENT) {
 				cmc.deactivate();
-				List<String> newGroupNames = groupChooseC.getSelectedNames();
-				List<String> escapedNames = new ArrayList<>(newGroupNames.size());
-				for(String newGroupName:newGroupNames) {
-					escapedNames.add(StringHelper.escapeHtml(newGroupName));
-				}
-				String list = StringHelper.formatAsSortUniqCSVString(escapedNames);
-				easyGroupList.setValue(list == null ? "" : list);
-				easyGroupList.setUserObject(groupChooseC.getSelectedKeys());
+				KeysAndNames c =  getGroupKeysAndNames(groupChooseC.getSelectedKeys());
+				easyGroupList.setValue(c.getDecoratedNames());
+				easyGroupList.setUserObject(c);
 				easyGroupList.getRootForm().submit(ureq);
 				chooseGroupsLink.setI18nKey("choose");
 			} else if (Event.CANCELLED_EVENT == event) {
@@ -509,14 +493,9 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 		} else if (source == areaChooseC) {
 			if (event == Event.DONE_EVENT) {
 				cmc.deactivate();
-				List<String> newAreaNames = areaChooseC.getSelectedNames();
-				List<String> escapedNames = new ArrayList<>(newAreaNames.size());
-				for(String newAreaName:newAreaNames) {
-					escapedNames.add(StringHelper.escapeHtml(newAreaName));
-				}
-				String list = StringHelper.formatAsSortUniqCSVString(escapedNames);
-				easyAreaList.setValue(list == null ? "" : list);
-				easyAreaList.setUserObject(areaChooseC.getSelectedKeys());
+				KeysAndNames c = getAreaKeysAndNames(areaChooseC.getSelectedKeys());
+				easyAreaList.setValue(c.getDecoratedNames());
+				easyAreaList.setUserObject(c);
 				easyAreaList.getRootForm().submit(ureq);
 				chooseAreasLink.setI18nKey("choose");
 			} else if (event == Event.CANCELLED_EVENT) {
@@ -530,12 +509,17 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 				List<Long> c = new ArrayList<Long>();
 				c.addAll(getKeys(easyGroupList));
 				if (fixGroupError != null && fixGroupError.getUserObject() != null) {
-					c.removeAll(Arrays.asList((String[])fixGroupError.getUserObject()));
+					String[] keyArr = (String[])fixGroupError.getUserObject();
+					if(keyArr != null && keyArr.length > 0) {
+						List<Long> fixedKeys = toKeys(keyArr[0]);
+						c.removeAll(fixedKeys);
+					}
 				}
 				c.addAll(groupCreateCntrllr.getCreatedGroupKeys());
 				
-				easyGroupList.setValue(getGroupNames(c));
-				easyGroupList.setUserObject(c);
+				KeysAndNames keysAndNames = getGroupKeysAndNames(c);
+				easyGroupList.setValue(keysAndNames.getDecoratedNames());
+				easyGroupList.setUserObject(keysAndNames);
 				
 				if (groupCreateCntrllr.getCreatedGroupNames().size() > 0 && !hasGroups) {
 					chooseGroupsLink.setLinkTitle("select");
@@ -551,12 +535,17 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 				List<Long> c = new ArrayList<Long>();
 				c.addAll(getKeys(easyAreaList));
 				if (fixAreaError != null && fixAreaError.getUserObject() != null) {
-					c.removeAll(Arrays.asList((String[])fixAreaError.getUserObject()));
+					String[] keyArr = (String[])fixAreaError.getUserObject();
+					if(keyArr != null && keyArr.length > 0) {
+						List<Long> fixedKeys = toKeys(keyArr[0]);
+						c.removeAll(fixedKeys);
+					}
 				}
 				c.addAll(areaCreateCntrllr.getCreatedAreaKeys());
 				
-				easyAreaList.setValue(getAreaNames(c));
-				easyAreaList.setUserObject(c);
+				KeysAndNames keysAndNames = getAreaKeysAndNames(c);
+				easyAreaList.setValue(keysAndNames.getDecoratedNames());
+				easyAreaList.setUserObject(keysAndNames);
 				
 				if (areaCreateCntrllr.getCreatedAreaNames().size() > 0 && !hasAreas) {
 					chooseAreasLink.setLinkTitle("select");
@@ -604,13 +593,12 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 	}
 	
 	private List<Long> getKeys(StaticTextElement element) {
-		@SuppressWarnings("unchecked")
-		List<Long> keys = (List<Long>)element.getUserObject();
+		KeysAndNames keys = (KeysAndNames)element.getUserObject();
 		if(keys == null) {
-			keys = new ArrayList<Long>();
+			keys = new KeysAndNames();
 			element.setUserObject(keys);
 		}
-		return keys;
+		return keys.getKeys();
 	}
 	
 	private String toString(Collection<Long> keys) {
@@ -622,26 +610,71 @@ class ENEditGroupAreaFormController extends FormBasicController implements Gener
 		return sb.toString();
 	}
 	
-	private String getGroupNames(List<Long> keys) {
+	private List<Long> toKeys(String keysString) {
+		List<Long> keyList = new ArrayList<>();
+		String[] keys = keysString.split(",");
+		for(String key:keys) {
+			try {
+				keyList.add(Long.parseLong(key));
+			} catch (NumberFormatException e) {
+				logWarn("Cannot parse this key: " + key, e);
+			}
+		}
+		return keyList;
+	}
+	
+	private KeysAndNames getGroupKeysAndNames(List<Long> keys) {
 		StringBuilder sb = new StringBuilder();
+		KeysAndNames keysAndNames = new KeysAndNames();
+		keysAndNames.getKeys().addAll(keys);
+		
 		List<BusinessGroupShort> groups = businessGroupService.loadShortBusinessGroups(keys);
 		for(BusinessGroupShort group:groups) {
 			if(sb.length() > 0) sb.append("&nbsp;&nbsp;");
 			sb.append("<i class='o_icon o_icon-fw o_icon_group'>&nbsp;</i> ");
 			sb.append(StringHelper.escapeHtml(group.getName()));
+			keysAndNames.getNames().add(group.getName());
+			
 		}
-		return sb.toString();
+		keysAndNames.setDecoratedNames(sb.toString());
+		return keysAndNames;
 	}
 	
-	private String getAreaNames(List<Long> keys) {
+	private KeysAndNames getAreaKeysAndNames(List<Long> keys) {
 		StringBuilder sb = new StringBuilder();
 		List<BGArea> areas = areaManager.loadAreas(keys);
+		KeysAndNames keysAndNames = new KeysAndNames();
+		keysAndNames.getKeys().addAll(keys);
 		for(BGArea area:areas) {
 			if(sb.length() > 0) sb.append("&nbsp;&nbsp;");
 			sb.append("<i class='o_icon o_icon-fw o_icon_courseareas'>&nbsp;</i> ");
 			sb.append(StringHelper.escapeHtml(area.getName()));
+			keysAndNames.getNames().add(area.getName());
 		}
-		return sb.toString();
+		keysAndNames.setDecoratedNames(sb.toString());
+		return keysAndNames;
 	}
+	
+	private static class KeysAndNames {
+		
+		private final List<Long> keys = new ArrayList<>();
+		private final List<String> names = new ArrayList<>();
+		private String decoratedNames;
+		
+		public List<Long> getKeys() {
+			return keys;
+		}
+		
+		public List<String> getNames() {
+			return names;
+		}
 
-}
+		public String getDecoratedNames() {
+			return decoratedNames;
+		}
+
+		public void setDecoratedNames(String decoratedNames) {
+			this.decoratedNames = decoratedNames;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
index 3cb929df4d58f3d5e17adfa632a7cef66cde29ab..ae695567c839f4787b4a5224f95afd99999ee37a 100644
--- a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
+++ b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
@@ -268,6 +268,10 @@ public class EnrollmentManager extends BasicManager {
 		  .append(" (select count(participants.key) from bgroupmember participants ")
 		  .append("  where participants.group=baseGroup and participants.role='").append(GroupRoles.participant.name()).append("'")
 		  .append(" ) as numOfParticipants,")
+		  //num of pending
+		  .append(" (select count(reservations.key) from resourcereservation reservations ")
+		  .append("  where reservations.resource.key=grp.resource.key")
+		  .append(" ) as numOfReservationss,")
 		  //length of the waiting list
 		  .append(" (select count(waiters.key) from bgroupmember waiters ")
 		  .append("  where grp.waitingListEnabled=true and waiters.group=baseGroup and waiters.role='").append(GroupRoles.waiting.name()).append("'")
@@ -319,13 +323,15 @@ public class EnrollmentManager extends BasicManager {
 			}
 			
 			int numOfParticipants = row[5] == null ? 0 : ((Number)row[5]).intValue();
-			int numOfWaiters = row[6] == null ? 0 : ((Number)row[6]).intValue();
-			boolean participant = row[7] == null ? false : ((Number)row[7]).intValue() > 0;
-			boolean waiting = row[8] == null ? false : ((Number)row[8]).intValue() > 0;
+			int numOfReservations = row[6] == null ? 0 : ((Number)row[6]).intValue();
+			int numOfWaiters = row[7] == null ? 0 : ((Number)row[7]).intValue();
+			boolean participant = row[8] == null ? false : ((Number)row[8]).intValue() > 0;
+			boolean waiting = row[9] == null ? false : ((Number)row[9]).intValue() > 0;
 			
 			EnrollmentRow enrollment = new EnrollmentRow(key, name, desc,
 					maxParticipants, waitingListEnabled);
 			enrollment.setNumOfParticipants(numOfParticipants);
+			enrollment.setNumOfReservations(numOfReservations);
 			enrollment.setNumInWaitingList(numOfWaiters);
 			enrollment.setParticipant(participant);
 			enrollment.setWaiting(waiting);
diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentRow.java b/src/main/java/org/olat/course/nodes/en/EnrollmentRow.java
index 7b1a9076ec6a977b961942295ab5cbd9ff94371f..ab7883eb57777fae4d0917e95eb55fa6322ed380 100644
--- a/src/main/java/org/olat/course/nodes/en/EnrollmentRow.java
+++ b/src/main/java/org/olat/course/nodes/en/EnrollmentRow.java
@@ -41,6 +41,7 @@ public class EnrollmentRow implements BusinessGroupRef {
 	private boolean participant;
 	private int numInWaitingList;
 	private int numOfParticipants;
+	private int numOfReservations;
 	private int positionInWaitingList;
 	
 	public EnrollmentRow(Long groupKey, String name, String description,
@@ -81,10 +82,6 @@ public class EnrollmentRow implements BusinessGroupRef {
 		this.waiting = waiting;
 	}
 	
-	public int getPositionInWaitingList() {
-		return positionInWaitingList;
-	}
-	
 	public boolean isParticipant() {
 		return participant;
 	}
@@ -94,7 +91,7 @@ public class EnrollmentRow implements BusinessGroupRef {
 	}
 	
 	public int getNumInWaitingList() {
-		return numInWaitingList;
+		return numInWaitingList < 0 ? 0 : numInWaitingList;
 	}
 	
 	public void setNumInWaitingList(int numInWaitingList) {
@@ -102,13 +99,25 @@ public class EnrollmentRow implements BusinessGroupRef {
 	}
 
 	public int getNumOfParticipants() {
-		return numOfParticipants;
+		return numOfParticipants < 0 ? 0 : numOfParticipants;
 	}
 
 	public void setNumOfParticipants(int numOfParticipants) {
 		this.numOfParticipants = numOfParticipants;
 	}
 
+	public int getNumOfReservations() {
+		return numOfReservations < 0 ? 0 : numOfReservations;
+	}
+
+	public void setNumOfReservations(int numOfReservations) {
+		this.numOfReservations = numOfReservations;
+	}
+	
+	public int getPositionInWaitingList() {
+		return positionInWaitingList;
+	}
+
 	public void setPositionInWaitingList(int positionInWaitingList) {
 		this.positionInWaitingList = positionInWaitingList;
 	}
diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentTableModelWithMaxSize.java b/src/main/java/org/olat/course/nodes/en/EnrollmentTableModelWithMaxSize.java
index d1b794f6559b0a554c65b07351825860657d24cb..07e3c053e58d6999724f159230398e2c6423a2f6 100644
--- a/src/main/java/org/olat/course/nodes/en/EnrollmentTableModelWithMaxSize.java
+++ b/src/main/java/org/olat/course/nodes/en/EnrollmentTableModelWithMaxSize.java
@@ -83,24 +83,24 @@ public class EnrollmentTableModelWithMaxSize extends DefaultTableDataModel<Enrol
 	@Override
 	public Object getValueAt(int row, int col) {
 		EnrollmentRow enrollmentRow = objects.get(row);
-		int numbParts = enrollmentRow.getNumOfParticipants();
-		Integer max = enrollmentRow.getMaxParticipants();
+		int numOfParticipants = enrollmentRow.getNumOfParticipants() + enrollmentRow.getNumOfReservations();
+		int max = enrollmentRow.getMaxParticipants();
 		switch (col) {
 			case 0: return enrollmentRow.getName();
 			case 1: return enrollmentRow.getDescription();
 			case 2:
 				// Belegt/Plätze
-				if (max == null) { 
+				if (max < 0) { 
 					// no limit => return only members
-					return numbParts; 
+					return numOfParticipants; 
 				}
 				// return format 2/10
 				StringBuilder buf = new StringBuilder();
-				buf.append(numbParts)
+				buf.append(numOfParticipants)
 				   .append(trans.translate("grouplist.table.partipiciant.delimiter"))
-				   .append(enrollmentRow.getMaxParticipants());
-				if(numbParts > enrollmentRow.getMaxParticipants()) {
-					log.info("Group overflow detected for the group: " + enrollmentRow.getKey() + "[name=" + enrollmentRow.getName() + "], participants: " + numbParts + " maxParticipamts: " + enrollmentRow.getMaxParticipants());
+				   .append(max);
+				if(numOfParticipants > max) {
+					log.info("Group overflow detected for the group: " + enrollmentRow.getKey() + "[name=" + enrollmentRow.getName() + "], participants: " + numOfParticipants + " maxParticipamts: " + enrollmentRow.getMaxParticipants());
 				}
 				return buf.toString();
 			case 3:
@@ -118,9 +118,9 @@ public class EnrollmentTableModelWithMaxSize extends DefaultTableDataModel<Enrol
 					int pos = enrollmentRow.getPositionInWaitingList();
 					String[] onWaitingListArgs = new String[] { Integer.toString(pos) };
 					return trans.translate("grouplist.table.state.onWaitingList",onWaitingListArgs); 
-				} else if (max != null && !enrollmentRow.isWaitingListEnabled() && numbParts >= max.intValue()) {
+				} else if (max  >= 0 && !enrollmentRow.isWaitingListEnabled() && numOfParticipants >= max) {
 					return trans.translate("grouplist.table.state.enroll.full"); 
-				}	else if (max != null && enrollmentRow.isWaitingListEnabled() && numbParts >= max.intValue()) {
+				}	else if (max  >= 0 && enrollmentRow.isWaitingListEnabled() && numOfParticipants >= max) {
 					return trans.translate("grouplist.table.state.WaitingList");
 				}
 				return trans.translate("grouplist.table.state.notEnrolled");
@@ -130,7 +130,7 @@ public class EnrollmentTableModelWithMaxSize extends DefaultTableDataModel<Enrol
 					// Already too much enrollments or already enrolled in the bg of the row => does not show action-link 'enroll'
 					return Boolean.FALSE;
 				}
-				if (max != null && !enrollmentRow.isWaitingListEnabled() && numbParts >= max.intValue()) {
+				if (max >= 0 && !enrollmentRow.isWaitingListEnabled() && numOfParticipants >= max) {
 					// group is full => => does not show action-link 'enroll'
 					return Boolean.FALSE;
 				}
diff --git a/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_de.properties
index 6e1e32502c5231c64fa7816b3bdcd93a5863bf45..8e6fdbe35353ad05c76e8ffdc6659f28287dd607 100644
--- a/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_de.properties
@@ -20,7 +20,7 @@ cmd.enrolled.cancel=Austragen
 condition.accessibility.title=Zugang
 config.header1=Einschreibung in Lerngruppen und Lernbereiche
 enroll.explain=W\u00E4hlen Sie eine der untenstehenden Lerngruppen aus, um sich einzuschreiben.
-enrolled.explain=Sie sind in die untenstehenden Lerngruppen eingeschrieben. W\u00E4hlen Sie - sofern vorhanden - den Link Austragen, um sich aus der entsprechenden Gruppe auszutragen. <b>Achtung\:</b> Diese Einschreibung betrifft einzig die gew\u00E4hlten Gruppen im entsprechenden OLAT-Kurs.
+enrolled.explain=Sie sind in die untenstehende(n) Lerngruppe(n) eingeschrieben. W\u00E4hlen Sie - sofern vorhanden - den Link Austragen, um sich aus der entsprechenden Gruppe auszutragen. <b>Achtung\:</b> Diese Einschreibung betrifft einzig die gew\u00E4hlten Gruppen im entsprechenden OpenOLAT-Kurs.
 enrolled.group.desc=Beschreibung
 enrolled.group.name=Namen der Lerngruppen
 enrolled.waitinglist.name=Namen der Wartelisten
@@ -57,22 +57,22 @@ grouplist.table.state.onPartipiciantList=<b>Eingeschrieben</b>
 grouplist.table.state.onWaitingList=<b>Auf Warteliste ({0})</b>
 grouplist.table.waitingList=Belegt auf<br />Warteliste
 help.hover.en=Hilfe zur Angabe der Lerngruppen und Lernbereiche
-notification.mail.added.self.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie haben sich in OLAT in eine Lerngruppe eingetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
-notification.mail.added.self.subject=OLAT-Lerngruppe {0}
+notification.mail.added.self.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie haben sich in OpenOLAT in eine Lerngruppe eingetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
+notification.mail.added.self.subject=OpenOLAT-Lerngruppe {0}
 notification.mail.error=Die E-Mail konnte nicht verschickt werden.
-notification.mail.removed.self.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie haben sich soeben aus der Lerngruppe ausgetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
-notification.mail.removed.self.subject=OLAT-Lerngruppe {0}\: Sie haben sich ausgetragen.
+notification.mail.removed.self.body=*** Dies ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie haben sich soeben aus folgender Lerngruppe ausgetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
+notification.mail.removed.self.subject=OpenOLAT-Lerngruppe {0}\: Sie haben sich ausgetragen.
 notification.mail.self.error=Die E-Mail konnte nicht an Sie verschickt werden.
-notification.mail.waitingList.added.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie sind in der Warteliste der folgenden Lerngruppe eingetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
-notification.mail.waitingList.added.subject=OLAT-Lerngruppe {0} Warteliste
-notification.mail.waitingList.removed.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie sind aus der Warteliste der folgenden Lerngruppe ausgetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
-notification.mail.waitingList.removed.subject=OLAT-Lerngruppe {0} Warteliste\: Sie haben sich ausgetragen.
-notification.mail.waitingList.transfer.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie wurden von der Warteliste in die Teilnehmerliste der folgenden Lerngruppe \u00FCbernommen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
-notification.mail.waitingList.transfer.subject=OLAT-Lerngruppe {0} Warteliste Status\u00E4nderung
+notification.mail.waitingList.added.body=*** Dies ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie sind in der Warteliste der folgenden Lerngruppe eingetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
+notification.mail.waitingList.added.subject=OpenOLAT-Lerngruppe {0} Warteliste
+notification.mail.waitingList.removed.body=*** Dies ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie sind aus der Warteliste der folgenden Lerngruppe ausgetragen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
+notification.mail.waitingList.removed.subject=OpenOLAT-Lerngruppe {0} Warteliste\: Sie haben sich ausgetragen.
+notification.mail.waitingList.transfer.body=*** Dies ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie wurden von der Warteliste in die Teilnehmerliste der folgenden Lerngruppe \u00FCbernommen\: \n\nGruppenname\: {0}\nBeschreibung\: {1}\n\n
+notification.mail.waitingList.transfer.subject=OpenOLAT-Lerngruppe {0} Warteliste Status\u00E4nderung
 pane.tab.accessibility=Zugang
 pane.tab.enconfig=Konfiguration
 popupchooseareas=Lernbereich aus Gruppenmanagement w\u00E4hlen
 popupchoosegroups=Gruppe aus Gruppenmanagement w\u00E4hlen
 waitinglist.explain=Sie sind in untenstehender Lerngruppe auf der Warteliste eingeschrieben. W\u00E4hlen Sie den Link Austragen, um sich aus der Warteliste auszutragen. 
-multiple.select.hint=Sie k\u00F6nnen sich in eine der unten aufgeführen Lerngruppen einschreiben. Sie k\u00F6nnen sich in maximal <b>{0}</b> Gruppen einschreiben.
-multiple.select.hint.outstanding=Sie haben sich in <b>{0}</b> Gruppen eingeschrieben. Sie k\u00F6nnen sich noch in <b>{1}</b> Gruppen einschreiben.
\ No newline at end of file
+multiple.select.hint=W\u00E4hlen Sie aus in welche der unten aufgef\u00FChrten Lerngruppen Sie sich einschreiben m\u00F6chten. Sie k\u00F6nnen sich in maximal <b>{0}</b> Gruppen einschreiben.
+multiple.select.hint.outstanding=Sie haben sich in <b>{0}</b> Gruppe(n) eingeschrieben. Sie k\u00F6nnen sich noch in <b>{1}</b> Gruppe(n) einschreiben.
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_en.properties
index e3afcc02009adcfdb44885a4da92e373fe14e7f1..f7975ed2939d4305ff6c9218073ebe939a9c202f 100644
--- a/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/en/_i18n/LocalStrings_en.properties
@@ -5,11 +5,11 @@ chelp.chsLearnar=Existing $\:chelp.learnar can be selected by clicking the butto
 chelp.chsLearngr=Existing $\:chelp.learngr can be selected by clicking the button $\:chelp.choose . The button $\:chelp.create will appear if there are no $\:chelp.learngr yet.
 chelp.create=<b>$org.olat.course.condition\:create</b>
 chelp.en=<i>$org.olat.course.nodes\:title_en</i>
-chelp.en1=Here you can enter which $\:chelp.learngr users can enroll for. Participants can then put their names down in one of the available $\:chelp.learngr .
+chelp.en1=Here you can enter which $\:chelp.learngr users can enrol for. Participants can then put their names down in one of the available $\:chelp.learngr .
 chelp.en2=Please enter the names of your $\:chelp.learngr (separated by commas).
 chelp.en3=Please enter the names of your $\:chelp.learnar (separated by commas).
 chelp.en4=You can edit any existing or newly created $\:chelp.learngr and $\:chelp.learnar in the $\:chelp.grmngmt .
-chelp.en5=Here you can decide if users are allowed to leave the group they have just enrolled for.
+chelp.en5=Here you can decide if users are allowed to leave the group they have just enroled for.
 chelp.en6=Course participants can then put their names down in $\:chelp.learngr belonging to this learning area.
 chelp.grmngmt=$org.olat.group.ui\:menu.index
 chelp.learnar=$org.olat.course.nodes.en\:form.areanames
@@ -19,7 +19,7 @@ cmd.enrolled.cancel=Cancel
 condition.accessibility.title=Access
 config.header1=Enrolment in learning groups and learning areas
 enroll.explain=Choose one of the learning groups below to enrol.
-enrolled.explain=You have already enrolled for the learning groups mentioned below. To cancel your enrollment please click on the button below (if available). <b>Attention\:</b> Your enrolment concerns only the groups selected in the corresponding OLAT course.
+enrolled.explain=You have already enroled for the learning groups mentioned below. To cancel your enrolment please click on the button below (if available). <b>Attention\:</b> Your enrolment concerns only the groups selected in the corresponding OpenOLAT course.
 enrolled.group.desc=Description
 enrolled.group.name=Names of learning groups
 enrolled.waitinglist.name=Names of waiting lists
@@ -32,7 +32,7 @@ form.areanames=Learning areas
 form.areanames.example=(Example\: Study trips)
 form.areanames.wrong=Enter names of learning areas separated by commas or leave this field empty.
 form.enableCancelEnroll=Delisting permitted
-form.allowMultiEnroll=Allow multiple enrollments
+form.allowMultiEnroll=Allow multiple enrolments
 form.multipleEnrollCount=Number of groups
 form.groupnames=Learning groups
 form.groupnames.example=(Example\: Green,Red,Blue)
@@ -51,28 +51,28 @@ grouplist.table.partipiciant.delimiter=/
 grouplist.table.state=Status
 grouplist.table.state.WaitingList=<i>Learning group is complete</i><br />Waiting list possible
 grouplist.table.state.enroll.full=<i>Learning group is complete</i><br />No waiting list
-grouplist.table.state.notEnrolled=Not enrolled
-grouplist.table.state.onPartipiciantList=<b>enrolled</b>
+grouplist.table.state.notEnrolled=Not enroled
+grouplist.table.state.onPartipiciantList=<b>enroled</b>
 grouplist.table.state.onWaitingList=<b>On waiting list ({0})</b>
 grouplist.table.waitingList=Taken on<br />waiting list
 help.hover.en=Help to choose learning groups and learning areas
-notification.mail.added.self.body=*** This is an automated message, please do not reply *** \r\n\r\nYou have enroled for an OLAT learning group\: \r\n\r\nGroup name\: {0}\r\nDescription\: {1}
-notification.mail.added.self.subject=OLAT learning group {0}
+notification.mail.added.self.body=*** This is an automated message, please do not reply *** \r\n\r\nYou have enroled for an OpenOLAT learning group\: \r\n\r\nGroup name\: {0}\r\nDescription\: {1}
+notification.mail.added.self.subject=OpenOLAT learning group {0}
 notification.mail.error=This e-mail could not be sent.
 notification.mail.removed.self.body=*** This is an automated message, please do not reply *** \r\n\r\nYou have just left a learning group\: \r\n\r\nGroup name\: {0}\r\nDescription\: {1}
-notification.mail.removed.self.subject=OLAT learning group {0}\: You have left this group for good.
+notification.mail.removed.self.subject=OpenOLAT learning group {0}\: You have left this group for good.
 notification.mail.self.error=This e-mail could not be sent.
 notification.mail.waitingList.added.body=*** This is an automated message, please do not reply *** \r\n\r\n You are on the waiting list of the following learning group\: \r\n\r\nGroup\: {0}\r\nDescription\: {1}
-notification.mail.waitingList.added.subject=OLAT learning group {0} waiting list
+notification.mail.waitingList.added.subject=OpenOLAT learning group {0} waiting list
 notification.mail.waitingList.removed.body=*** This is an automated message, please do not reply *** \r\n\r\n You are no longer on the waiting list of the following learning group\: \r\n\r\nGroup\: {0}\r\nDescription\: {1}
-notification.mail.waitingList.removed.subject=OLAT learning group{0} waiting list\: you have cancelled your enrolment.
+notification.mail.waitingList.removed.subject=OpenOLAT learning group{0} waiting list\: you have cancelled your enrolment.
 notification.mail.waitingList.transfer.body=*** This is an automated message, please do not reply *** \r\n\r\n You have been transferred from the waiting list to the list of participants of the following learning group\: \r\n\r\nGroup\: {0}\r\nDescription\: {1}
-notification.mail.waitingList.transfer.subject=OLAT learning group {0} waiting list modification of status
+notification.mail.waitingList.transfer.subject=OpenOLAT learning group {0} waiting list modification of status
 pane.tab.accessibility=Access
 pane.tab.enconfig=Configuration
 popupchooseareas=Select learning areas from group management
 popupchoosegroups=Select groups from group management
 title_en=Enrolment
 waitinglist.explain=You are on the waiting list of the learning group mentioned below. Click 'Cancel enrolment' in order to delist.
-multiple.select.hint=Choose from the learning groups below to enroll. You are allowed to enroll to a total of <b>{0}</b> groups.
-multiple.select.hint.outstanding=You have enrolled to <b>{0}</b> Group. You can enroll to <b>{1}</b> more groups.
\ No newline at end of file
+multiple.select.hint=Choose from the learning groups below to enrol. You are allowed to enrol to a total of <b>{0}</b> groups.
+multiple.select.hint.outstanding=You have enroled to <b>{0}</b> Group. You can enrol to <b>{1}</b> more groups.
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
index 474811c833a7edfa3812b4eed25749ddbcd2550c..f265bec23aa384b4f8c3e2c5b90dc12953bee08a 100644
--- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java
+++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
@@ -160,7 +160,10 @@ public interface GTAManager {
 	
 	
 
-	public List<Task> getTasks(TaskList taskList);
+	public List<Task> getTasks(TaskList taskList, GTACourseNode gtaNode);
+	
+	public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode);
+
 	
 	/**
 	 * Return the tasks assigned to a person, individually or via a
diff --git a/src/main/java/org/olat/course/nodes/gta/TaskLight.java b/src/main/java/org/olat/course/nodes/gta/TaskLight.java
new file mode 100644
index 0000000000000000000000000000000000000000..33f6b19774ab29d4fcbcea62a1b47441a48a7482
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/TaskLight.java
@@ -0,0 +1,52 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta;
+
+import java.util.Date;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface TaskLight {
+	
+	public Long getKey();
+	
+	public Date getCreationDate();
+	
+	public Date getLastModified();
+	
+	public TaskProcess getTaskStatus();
+	
+	/**
+	 * Iteration of the revision / correction process. Start with 1.
+	 * @return
+	 */
+	public int getRevisionLoop();
+	
+	public String getTaskName();
+	
+	public Long getIdentityKey();
+	
+	public Long getBusinessGroupKey();
+
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
index 595b0d213756b8218f4e5cdf1796a842c3965cd8..2b786bed6c3d81acb112376eca897eeae2f4e6e4 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
@@ -51,6 +51,7 @@ import org.olat.course.nodes.gta.AssignmentResponse.Status;
 import org.olat.course.nodes.gta.GTAManager;
 import org.olat.course.nodes.gta.GTAType;
 import org.olat.course.nodes.gta.Task;
+import org.olat.course.nodes.gta.TaskLight;
 import org.olat.course.nodes.gta.TaskList;
 import org.olat.course.nodes.gta.TaskProcess;
 import org.olat.course.nodes.gta.model.Membership;
@@ -462,17 +463,34 @@ public class GTAManagerImpl implements GTAManager {
 	}
 
 	@Override
-	public List<Task> getTasks(TaskList taskList) {
+	public List<Task> getTasks(TaskList taskList, GTACourseNode cNode) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select task from gtatask task ")
-		  .append(" inner join task.taskList tasklist ")
-		  .append(" where tasklist.key=:taskListKey ");
-		
+		  .append(" inner join task.taskList tasklist ");
+		if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
+			sb.append(" inner join fetch task.businessGroup bGroup ");
+		} else {
+			sb.append(" inner join fetch task.identity identity ");
+		}
+		sb.append(" where tasklist.key=:taskListKey");
 		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Task.class)
 				.setParameter("taskListKey", taskList.getKey())
 				.getResultList();
 	}
 
+	@Override
+	public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select task from gtatasklight task ")
+		  .append(" inner join task.taskList tasklist ")
+		  .append(" where tasklist.entry.key=:entryKey and tasklist.courseNodeIdent=:courseNodeIdent");
+		
+		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), TaskLight.class)
+				.setParameter("entryKey", entry.getKey())
+				.setParameter("courseNodeIdent", gtaNode.getIdent())
+				.getResultList();
+	}
+
 	@Override
 	public List<Task> getTasks(IdentityRef identity, RepositoryEntryRef entry, GTACourseNode cNode) {
 		StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java b/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b17d8ab7f244930731f2a40760eb52edfaa1dd4
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java
@@ -0,0 +1,202 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.core.id.CreateInfo;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.core.id.Persistable;
+import org.olat.core.util.StringHelper;
+import org.olat.course.nodes.gta.TaskLight;
+import org.olat.course.nodes.gta.TaskList;
+import org.olat.course.nodes.gta.TaskProcess;
+
+/**
+ * 
+ * Initial date: 25.02.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+
+@Entity(name="gtatasklight")
+@Table(name="o_gta_task")
+public class TaskLightImpl implements TaskLight, CreateInfo, Persistable, ModifiedInfo {
+
+	private static final long serialVersionUID = 4202873369981813454L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=false, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=false, updatable=false)
+	private Date lastModified;
+	
+	@Column(name="g_status", nullable=false, insertable=false, updatable=false)
+	private String status;
+	
+	@Column(name="g_rev_loop", nullable=false, insertable=false, updatable=false)
+	private int revisionLoop;
+	
+	@Column(name="g_taskname", nullable=true, insertable=false, updatable=false)
+	private String taskName;
+
+	@ManyToOne(targetEntity=TaskListImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_tasklist", nullable=false, insertable=true, updatable=false)
+	private TaskList taskList;
+	
+	@Column(name="fk_identity", nullable=true, insertable=false, updatable=false)
+	private Long identityKey;
+	
+	@Column(name="fk_businessgroup", nullable=true, insertable=false, updatable=false)
+	private Long businessGroupKey;
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+	
+	public void setCreationDate(Date date) {
+		this.creationDate = date;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date date) {
+		this.lastModified = date;
+	}
+
+	public TaskList getTaskList() {
+		return taskList;
+	}
+
+	public void setTaskList(TaskList taskList) {
+		this.taskList = taskList;
+	}
+
+	@Override
+	public Long getIdentityKey() {
+		return identityKey;
+	}
+
+	public void setIdentityKey(Long identityKey) {
+		this.identityKey = identityKey;
+	}
+
+	@Override
+	public Long getBusinessGroupKey() {
+		return businessGroupKey;
+	}
+
+	public void setBusinessGroupKey(Long businessGroupKey) {
+		this.businessGroupKey = businessGroupKey;
+	}
+
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
+	@Override
+	public String getTaskName() {
+		return taskName;
+	}
+
+	public void setTaskName(String taskName) {
+		this.taskName = taskName;
+	}
+
+	@Override
+	public TaskProcess getTaskStatus() {
+		if(StringHelper.containsNonWhitespace(status)) {
+			return TaskProcess.valueOf(status);
+		}
+		return null;
+	}
+	
+	public void setTaskStatus(TaskProcess taskStatus) {
+		if(taskStatus == null) {
+			status = null;
+		} else {
+			status = taskStatus.name();
+		}
+	}
+	
+	@Override
+	public int getRevisionLoop() {
+		return revisionLoop;
+	}
+
+	public void setRevisionLoop(int revisionLoop) {
+		this.revisionLoop = revisionLoop;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? 83544 : key.hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof TaskLightImpl) {
+			TaskLightImpl task = (TaskLightImpl)obj;
+			return key != null && key.equals(task.getKey());
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java
index 364de565118c75f16b2b508ca3eae448f7cca5e4..1f8f8c34f1c2b5cb71cdde8de7ac1c15dc59b643 100644
--- a/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java
+++ b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java
@@ -112,7 +112,7 @@ public abstract class AbstractDueDateTaskRuleSPI implements IdentitiesProviderRu
 		if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) {
 			return getGroupsToRemind(taskList, gtaNode);
 		} else {
-			return getIndividualsToRemind(taskList, entry);
+			return getIndividualsToRemind(taskList, entry, gtaNode);
 		}
 	}
 	
@@ -206,7 +206,7 @@ public abstract class AbstractDueDateTaskRuleSPI implements IdentitiesProviderRu
 	}
 	
 	protected List<Identity> getGroupsToRemind(TaskList taskList, GTACourseNode gtaNode) {
-		List<Task> tasks = gtaManager.getTasks(taskList);
+		List<Task> tasks = gtaManager.getTasks(taskList, gtaNode);
 		Set<BusinessGroup> doneTasks = new HashSet<BusinessGroup>();
 		for(Task task:tasks) {
 			if(task.getBusinessGroup() != null) {
@@ -224,8 +224,8 @@ public abstract class AbstractDueDateTaskRuleSPI implements IdentitiesProviderRu
 		return businessGroupService.getMembers(groups, GroupRoles.participant.name());
 	}
 	
-	protected List<Identity> getIndividualsToRemind(TaskList taskList, RepositoryEntry entry) {
-		List<Task> tasks = gtaManager.getTasks(taskList);
+	protected List<Identity> getIndividualsToRemind(TaskList taskList, RepositoryEntry entry, GTACourseNode gtaNode) {
+		List<Task> tasks = gtaManager.getTasks(taskList, gtaNode);
 		Set<Identity> doneTasks = new HashSet<Identity>();
 		for(Task task:tasks) {
 			if(task.getIdentity() != null) {
diff --git a/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java
index 6d8feebbe2720f62d3ef3a14ab120dba887b9d6b..03716a7e7f22b01555bc4323be5337fec643771e 100644
--- a/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java
+++ b/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java
@@ -24,6 +24,7 @@ import java.util.List;
 
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.ui.BeforeDateTaskRuleEditor;
 import org.olat.modules.ModuleConfiguration;
@@ -56,6 +57,12 @@ public class AssignTaskRuleSPI extends AbstractDueDateTaskRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new BeforeDateTaskRuleEditor(rule, entry, AssignTaskRuleSPI.class.getSimpleName());
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		//node ident must be the same
+		return rule.clone();
+	}
 
 	@Override
 	protected Date getDueDate(GTACourseNode gtaNode) {
diff --git a/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java
index 326c05d16b11bf6e5ab381fc550396ab354dcaa5..65fc25feb01c810dccc589b3546f2085515974d6 100644
--- a/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java
+++ b/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java
@@ -24,6 +24,7 @@ import java.util.List;
 
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
 import org.olat.course.nodes.gta.ui.BeforeDateTaskRuleEditor;
@@ -67,6 +68,12 @@ public class SubmissionTaskRuleSPI extends AbstractDueDateTaskRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new BeforeDateTaskRuleEditor(rule, entry, SubmissionTaskRuleSPI.class.getSimpleName());
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		// node ident must be the same
+		return rule.clone();
+	}
 
 	@Override
 	protected Date getDueDate(GTACourseNode gtaNode) {
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java b/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java
index 81903de8019f2c85febf1b2b5c7689b29087bc3b..c85f2e68ac674500571fec71f518e28e7ee88fd4 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java
@@ -106,7 +106,7 @@ public class BeforeDateTaskRuleEditor extends RuleEditorFragment {
 		String[] nodeValues = new String[attemptableNodes.size()];
 		
 		for(int i=0; i<attemptableNodes.size(); i++) {
-			CourseNode attemptableNode = attemptableNodes.get(0);
+			CourseNode attemptableNode = attemptableNodes.get(i);
 			nodeKeys[i] = attemptableNode.getIdent();
 			nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )";
 		}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsModelSort.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsModelSort.java
new file mode 100644
index 0000000000000000000000000000000000000000..a71b93c8953cf5947be7cc97024ff7c994ec1ecb
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsModelSort.java
@@ -0,0 +1,82 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.course.nodes.gta.TaskLight;
+import org.olat.course.nodes.gta.TaskProcess;
+import org.olat.course.nodes.gta.ui.CoachGroupsTableModel.CGCols;
+
+/**
+ * 
+ * Initial date: 30.01.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CoachGroupsModelSort extends SortableFlexiTableModelDelegate<CoachedGroupRow> {
+	
+	public CoachGroupsModelSort(SortKey orderBy, SortableFlexiTableDataModel<CoachedGroupRow> tableModel, Locale locale) {
+		super(orderBy, tableModel, locale);
+	}
+
+	@Override
+	protected void sort(List<CoachedGroupRow> rows) {
+		int columnIndex = getColumnIndex();
+		CGCols column = CGCols.values()[columnIndex];
+		switch(column) {
+			case taskStatus: Collections.sort(rows, new TaskStatusComparator()); break;
+			default: {
+				super.sort(rows);
+			}
+		}
+	}
+	
+	private static class TaskStatusComparator implements Comparator<CoachedGroupRow> {
+		@Override
+		public int compare(CoachedGroupRow o1, CoachedGroupRow o2) {
+			TaskLight t1 = o1.getTask();
+			TaskLight t2 = o2.getTask();
+			
+			if(t1 == null) {
+				if(t2 == null) return 0;
+				return -1;
+			}
+			if(t2 == null) return 1;
+			
+			TaskProcess s1 = t1.getTaskStatus();
+			TaskProcess s2 = t2.getTaskStatus();
+			
+			if(s1 == null) {
+				if(s2 == null) return 0;
+				return -1;
+			}
+			if(s2 == null) return 1;
+			
+			return s1.ordinal() - s2.ordinal();
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java
index 05c988b971287f5b356bd87cabe42c2f9b99e4c7..b52ee6979d34f991523dffb02a5a5b4096cfc322 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java
@@ -19,9 +19,12 @@
  */
 package org.olat.course.nodes.gta.ui;
 
+import java.util.List;
+
+import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
-import org.olat.group.BusinessGroup;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
 
 /**
  * 
@@ -29,28 +32,43 @@ import org.olat.group.BusinessGroup;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CoachGroupsTableModel extends DefaultFlexiTableDataModel<BusinessGroup> {
+public class CoachGroupsTableModel extends DefaultFlexiTableDataModel<CoachedGroupRow> implements SortableFlexiTableDataModel<CoachedGroupRow> {
 	
 	public CoachGroupsTableModel(FlexiTableColumnModel columnModel) {
 		super(columnModel);
 	}
 
 	@Override
-	public DefaultFlexiTableDataModel<BusinessGroup> createCopyWithEmptyList() {
+	public DefaultFlexiTableDataModel<CoachedGroupRow> createCopyWithEmptyList() {
 		return new CoachGroupsTableModel(getTableColumnModel());
 	}
 
+	@Override
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<CoachedGroupRow> views = new CoachGroupsModelSort(orderBy, this, null).sort();
+			super.setObjects(views);
+		}
+	}
+
 	@Override
 	public Object getValueAt(int row, int col) {
-		BusinessGroup group = getObject(row);
+		CoachedGroupRow coachedGroup = getObject(row);
+		return getValueAt(coachedGroup, col);
+	}
+	
+	@Override
+	public Object getValueAt(CoachedGroupRow row, int col) {
 		switch(CGCols.values()[col]) {
-			case name: return group.getName();
+			case name: return row.getName();
+			case taskStatus: return row.getTaskStatus();
 			default: return "ERROR";
 		}
 	}
 	
 	public enum CGCols {
-		name("table.header.group.name");
+		name("table.header.group.name"),
+		taskStatus("table.header.group.step");
 		
 		private final String i18nKey;
 		
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsModelSort.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsModelSort.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b5a6e33715962bc6fa1b6f44063a26720970265
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsModelSort.java
@@ -0,0 +1,73 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.course.nodes.gta.TaskProcess;
+import org.olat.course.nodes.gta.ui.CoachParticipantsTableModel.CGCols;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CoachParticipantsModelSort extends SortableFlexiTableModelDelegate<CoachedIdentityRow> {
+	
+	public CoachParticipantsModelSort(SortKey orderBy, SortableFlexiTableDataModel<CoachedIdentityRow> tableModel, Locale locale) {
+		super(orderBy, tableModel, locale);
+	}
+	
+	@Override
+	protected void sort(List<CoachedIdentityRow> rows) {
+		int columnIndex = getColumnIndex();
+		CGCols column = CGCols.values()[columnIndex];
+		switch(column) {
+			case taskStatus: Collections.sort(rows, new TaskStatusComparator()); break;
+			default: {
+				super.sort(rows);
+			}
+		}
+	}
+	
+	private static class TaskStatusComparator implements Comparator<CoachedIdentityRow> {
+		@Override
+		public int compare(CoachedIdentityRow o1, CoachedIdentityRow o2) {
+			TaskProcess s1 = o1.getTaskStatus();
+			TaskProcess s2 = o2.getTaskStatus();
+			
+			if(s1 == null) {
+				if(s2 == null) return 0;
+				return -1;
+			}
+			if(s2 == null) return 1;
+			
+			return s1.ordinal() - s2.ordinal();
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java
index c4da8e3c7f33542d2e3b2abe0c98f0776436c551..8cffbcd74f322bfa8e799b5574bbeb13222d4733 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java
@@ -22,10 +22,10 @@ package org.olat.course.nodes.gta.ui;
 import java.util.List;
 import java.util.Locale;
 
+import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
-import org.olat.core.id.Identity;
-import org.olat.core.id.User;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 
 /**
@@ -34,7 +34,7 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Identity> {
+public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<CoachedIdentityRow> implements SortableFlexiTableDataModel<CoachedIdentityRow> {
 	
 	private final Locale locale;
 	private final List<UserPropertyHandler> userPropertyHandlers;
@@ -47,25 +47,40 @@ public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Iden
 	}
 
 	@Override
-	public DefaultFlexiTableDataModel<Identity> createCopyWithEmptyList() {
+	public DefaultFlexiTableDataModel<CoachedIdentityRow> createCopyWithEmptyList() {
 		return new CoachParticipantsTableModel(userPropertyHandlers, locale, getTableColumnModel());
 	}
+	
+	@Override
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<CoachedIdentityRow> views = new CoachParticipantsModelSort(orderBy, this, null).sort();
+			super.setObjects(views);
+		}
+	}
 
 	@Override
 	public Object getValueAt(int row, int col) {
-		Identity participant = getObject(row);
+		CoachedIdentityRow participant = getObject(row);
+		return getValueAt(participant, col);
+	}
+	
+	@Override
+	public Object getValueAt(CoachedIdentityRow row, int col) {
 		if(col == CGCols.username.ordinal()) {
-			return participant.getName();
+			return row.getIdentity().getIdentityName();
+		} else if(col == CGCols.taskStatus.ordinal()) {
+			return row.getTaskStatus();
 		} else if(col >= GTACoachedGroupGradingController.USER_PROPS_OFFSET) {
 			int propIndex = col - GTACoachedGroupGradingController.USER_PROPS_OFFSET;
-			User user = participant.getUser();
-			return userPropertyHandlers.get(propIndex).getUserProperty(user, locale);
+			return row.getIdentity().getIdentityProp(propIndex);
 		}
 		return "ERROR";
 	}
 	
 	public enum CGCols {
-		username("username");
+		username("username"),
+		taskStatus("table.header.group.step");
 		
 		private final String i18nKey;
 		
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..16f96a25250ac6eec5a1b101f5010225e924a68b
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java
@@ -0,0 +1,57 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import org.olat.course.nodes.gta.TaskLight;
+import org.olat.course.nodes.gta.TaskProcess;
+import org.olat.group.BusinessGroup;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CoachedGroupRow {
+	
+	private final TaskLight task;
+	private final BusinessGroup businessGroup;
+	
+	public CoachedGroupRow(BusinessGroup businessGroup, TaskLight task) {
+		this.task = task;
+		this.businessGroup = businessGroup;
+	}
+	
+	public String getName() {
+		return businessGroup.getName();
+	}
+	
+	public TaskProcess getTaskStatus() {
+		return task == null ? null : task.getTaskStatus();
+	}
+	
+	public TaskLight getTask() {
+		return task;
+	}
+	
+	public BusinessGroup getBusinessGroup() {
+		return businessGroup;
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..568a19d8ab9e21758abde30f8528fb3a72f5086d
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java
@@ -0,0 +1,49 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import org.olat.course.nodes.gta.TaskLight;
+import org.olat.course.nodes.gta.TaskProcess;
+import org.olat.user.UserPropertiesRow;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CoachedIdentityRow {
+
+	private final TaskLight task;
+	private final UserPropertiesRow identity;
+	
+	public CoachedIdentityRow(UserPropertiesRow identity, TaskLight task) {
+		this.identity = identity;
+		this.task = task;
+	}
+	
+	public TaskProcess getTaskStatus() {
+		return task == null ? null : task.getTaskStatus();
+	}
+	
+	public UserPropertiesRow getIdentity() {
+		return identity;
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
index e6b59af80155700694c2fc7ec3174c8bf7c8b7a7..23c089108ba6caf903beebc0f264394d95cc9ac2 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
@@ -114,7 +114,7 @@ public class GTAAssessmentDetailsController extends BasicController {
 			} else if(participatingGroups.size() == 1) {
 				doSelectBusinessGroup(ureq, participatingGroups.get(0));
 			} else {
-				groupListCtrl = new GTACoachedGroupListController(ureq, getWindowControl(), participatingGroups);
+				groupListCtrl = new GTACoachedGroupListController(ureq, getWindowControl(), courseEnv, gtaNode, participatingGroups);
 				listenTo(groupListCtrl);
 				mainVC.put("list", groupListCtrl.getInitialComponent());
 			}	
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
index 6f9a142ddeba307c76af651b401f6544048437db..ca1ffc1814fd2ed6e40eeb2baafd876f4eed14a7 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
@@ -283,7 +283,7 @@ public class GTACoachController extends GTAAbstractController {
 			} else {
 				mainVC.contextPut("solutionCssClass", "o_done");
 			}	
-		} else if (assignedTask == null || assignedTask.getTaskStatus() == TaskProcess.solution){
+		} else if (assignedTask == null || assignedTask.getTaskStatus() == TaskProcess.solution) {
 			mainVC.contextPut("solutionCssClass", "o_active");
 		} else {
 			mainVC.contextPut("solutionCssClass", "o_done");
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
index 555bec4184910f9b30079410f9456681d138e713..4010da05ffe59be9f7ece0c22f189b33679747ae 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
@@ -158,7 +158,7 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController {
 		
 		boolean hasDocuments = TaskHelper.hasDocuments(documentsDir);
 		if(hasDocuments) {
-			correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, "run.corrections.description", "bulk.review", "review");
+			correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, "run.coach.corrections.description", "bulk.review", "review");
 			listenTo(correctionsCtrl);
 			mainVC.put(cmpName, correctionsCtrl.getInitialComponent());
 		}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java
index 1fc72fb759f3df5393e748a179468d2f04edfb4b..789e2706478d839ae029f4501ab79fb213098d0a 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java
@@ -22,6 +22,7 @@ package org.olat.course.nodes.gta.ui;
 import java.util.Collections;
 import java.util.List;
 
+import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -63,6 +64,8 @@ public class GTACoachSelectionController extends BasicController {
 	
 	@Autowired
 	private GTAManager gtaManager;
+	@Autowired
+	private BaseSecurity securityManager;
 	
 	public GTACoachSelectionController(UserRequest ureq, WindowControl wControl,
 			UserCourseEnvironment coachCourseEnv, GTACourseNode gtaNode) {
@@ -90,12 +93,12 @@ public class GTACoachSelectionController extends BasicController {
 			if(groups.size() == 1) {
 				doSelectBusinessGroup(ureq, groups.get(0));
 			} else {
-				groupListCtrl = new GTACoachedGroupListController(ureq, getWindowControl(), groups);
+				groupListCtrl = new GTACoachedGroupListController(ureq, getWindowControl(), courseEnv, gtaNode, groups);
 				listenTo(groupListCtrl);
 				mainVC.put("list", groupListCtrl.getInitialComponent());
 			}	
 		} else {
-			participantListCtrl = new GTACoachedParticipantListController(ureq, getWindowControl(), coachCourseEnv);
+			participantListCtrl = new GTACoachedParticipantListController(ureq, getWindowControl(), coachCourseEnv, gtaNode);
 			listenTo(participantListCtrl);
 			mainVC.put("list", participantListCtrl.getInitialComponent());
 		}
@@ -119,7 +122,8 @@ public class GTACoachSelectionController extends BasicController {
 		} else if(participantListCtrl == source) {
 			if(event instanceof SelectIdentityEvent) {
 				SelectIdentityEvent selectEvent = (SelectIdentityEvent)event;
-				doSelectParticipant(ureq, selectEvent.getIdentity());
+				Identity selectedIdentity = securityManager.loadIdentityByKey(selectEvent.getIdentityKey());
+				doSelectParticipant(ureq, selectedIdentity);
 				backLink.setVisible(true);
 			}
 			
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
index 685e0b92e2e7b2bdfd7690531f1b1baf718c165d..d6f07c58c29dd4148916b3a30801c5ded67e4d51 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
@@ -19,7 +19,10 @@
  */
 package org.olat.course.nodes.gta.ui;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
@@ -34,8 +37,14 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionE
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.course.nodes.GTACourseNode;
+import org.olat.course.nodes.gta.GTAManager;
+import org.olat.course.nodes.gta.TaskLight;
 import org.olat.course.nodes.gta.ui.CoachGroupsTableModel.CGCols;
+import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.repository.RepositoryEntry;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -48,10 +57,18 @@ public class GTACoachedGroupListController extends FormBasicController {
 	private FlexiTableElement tableEl;
 	private CoachGroupsTableModel tableModel;
 	
+	private final GTACourseNode gtaNode;
+	private final CourseEnvironment courseEnv;
 	private final List<BusinessGroup> coachedGroups;
 	
-	public GTACoachedGroupListController(UserRequest ureq, WindowControl wControl, List<BusinessGroup> coachedGroups) {
+	@Autowired
+	private GTAManager gtaManager;
+	
+	public GTACoachedGroupListController(UserRequest ureq, WindowControl wControl,
+			CourseEnvironment courseEnv, GTACourseNode gtaNode, List<BusinessGroup> coachedGroups) {
 		super(ureq, wControl, LAYOUT_BAREBONE);
+		this.gtaNode = gtaNode;
+		this.courseEnv = courseEnv;
 		this.coachedGroups = coachedGroups;
 		initForm(ureq);
 		updateModel();
@@ -60,7 +77,10 @@ public class GTACoachedGroupListController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.name.i18nKey(), CGCols.name.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.name.i18nKey(), CGCols.name.ordinal(),
+				true,  CGCols.name.name()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(),
+				true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
 		tableModel = new CoachGroupsTableModel(columnsModel);
 
@@ -68,7 +88,22 @@ public class GTACoachedGroupListController extends FormBasicController {
 	}
 	
 	private void updateModel() {
-		tableModel.setObjects(coachedGroups);
+		RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry();
+		List<TaskLight> tasks = gtaManager.getTasksLight(entry, gtaNode);
+		Map<Long,TaskLight> groupToTasks = new HashMap<>();
+		for(TaskLight task:tasks) {
+			if(task.getBusinessGroupKey() != null) {
+				groupToTasks.put(task.getBusinessGroupKey(), task);
+			}
+		}
+
+		List<CoachedGroupRow> rows = new ArrayList<>(coachedGroups.size());
+		for(BusinessGroup group:coachedGroups) {
+			TaskLight task = groupToTasks.get(group.getKey());
+			rows.add(new CoachedGroupRow(group, task));
+		}
+		
+		tableModel.setObjects(rows);
 		tableEl.reset();
 	}
 
@@ -83,9 +118,9 @@ public class GTACoachedGroupListController extends FormBasicController {
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
 				String cmd = se.getCommand();
-				BusinessGroup row = tableModel.getObject(se.getIndex());
+				CoachedGroupRow row = tableModel.getObject(se.getIndex());
 				if("details".equals(cmd) || "select".equals(cmd)) {
-					fireEvent(ureq, new SelectBusinessGroupEvent(row));	
+					fireEvent(ureq, new SelectBusinessGroupEvent(row.getBusinessGroup()));	
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java
index 88b0c2871835892762e69e274df795e7e951535a..9566773e8ebd72bbef580810d5121659728e4a02 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java
@@ -138,7 +138,8 @@ public class GTACoachedParticipantGradingController extends BasicController {
 		UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
 		AssessedIdentityWrapper assessedIdentityWrapper = AssessmentHelper.wrapIdentity(uce, null, gtaNode);
 		
-		assessmentForm = new AssessmentEditController(ureq, getWindowControl(), null, course, gtaNode, assessedIdentityWrapper, false, true);
+		assessmentForm = new AssessmentEditController(ureq, getWindowControl(), null, course, gtaNode,
+				assessedIdentityWrapper, false, true, true);
 		listenTo(assessmentForm);
 		
 		String title = translate("grading");
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
index adb328ab8a2173dba53ee7aab8b9028064751930..890899a5f78c5075cfd84b5bf2c82b1d37c74069 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
@@ -20,8 +20,10 @@
 package org.olat.course.nodes.gta.ui;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.olat.basesecurity.BaseSecurityModule;
@@ -47,8 +49,11 @@ import org.olat.core.id.Roles;
 import org.olat.core.id.UserConstants;
 import org.olat.core.util.StringHelper;
 import org.olat.course.groupsandrights.CourseGroupManager;
+import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
+import org.olat.course.nodes.gta.TaskLight;
 import org.olat.course.nodes.gta.ui.CoachParticipantsTableModel.CGCols;
+import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.course.run.userview.UserCourseEnvironmentImpl;
 import org.olat.group.BusinessGroup;
@@ -56,6 +61,7 @@ import org.olat.group.BusinessGroupService;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryService;
 import org.olat.user.UserManager;
+import org.olat.user.UserPropertiesRow;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -69,8 +75,10 @@ public class GTACoachedParticipantListController extends FormBasicController {
 	
 	private FlexiTableElement tableEl;
 	private CoachParticipantsTableModel tableModel;
-	
-	private List<Identity> assessableIdentities;
+
+	private final GTACourseNode gtaNode;
+	private final CourseEnvironment courseEnv;
+	private List<UserPropertiesRow> assessableIdentities;
 	
 	private final boolean isAdministrativeUser;
 	private final List<UserPropertyHandler> userPropertyHandlers;
@@ -86,7 +94,8 @@ public class GTACoachedParticipantListController extends FormBasicController {
 	@Autowired
 	private BusinessGroupService businessGroupService;
 	
-	public GTACoachedParticipantListController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv) {
+	public GTACoachedParticipantListController(UserRequest ureq, WindowControl wControl,
+			UserCourseEnvironment userCourseEnv, GTACourseNode gtaNode) {
 		super(ureq, wControl, LAYOUT_BAREBONE);
 		
 		Roles roles = ureq.getUserSession().getRoles();
@@ -96,6 +105,8 @@ public class GTACoachedParticipantListController extends FormBasicController {
 		
 		CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
 		UserCourseEnvironmentImpl coachCourseEnv = (UserCourseEnvironmentImpl)userCourseEnv;
+		courseEnv = userCourseEnv.getCourseEnvironment();
+		this.gtaNode = gtaNode;
 		
 		boolean admin = userCourseEnv.isAdmin();
 
@@ -105,7 +116,7 @@ public class GTACoachedParticipantListController extends FormBasicController {
 		List<Identity> participants = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name());
 		for(Identity participant:participants) {
 			if(!duplicateKiller.contains(participant)) {
-				assessableIdentities.add(participant);
+				assessableIdentities.add(new UserPropertiesRow(participant, userPropertyHandlers, getLocale()));
 				duplicateKiller.add(participant);
 			}
 		}
@@ -116,7 +127,7 @@ public class GTACoachedParticipantListController extends FormBasicController {
 			List<Identity> courseParticipants = repositoryService.getMembers(re, GroupRoles.participant.name());
 			for(Identity participant:courseParticipants) {
 				if(!duplicateKiller.contains(participant)) {
-					assessableIdentities.add(participant);
+					assessableIdentities.add(new UserPropertiesRow(participant, userPropertyHandlers, getLocale()));
 					duplicateKiller.add(participant);
 				}
 			}
@@ -131,7 +142,8 @@ public class GTACoachedParticipantListController extends FormBasicController {
 
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(isAdministrativeUser) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.username.i18nKey(), CGCols.username.ordinal()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.username.i18nKey(), CGCols.username.ordinal(),
+					true, CGCols.username.name()));
 		}
 		
 		int i=0;
@@ -155,6 +167,8 @@ public class GTACoachedParticipantListController extends FormBasicController {
 			}
 		}
 		
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(),
+				true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
 		tableModel = new CoachParticipantsTableModel(userPropertyHandlers, getLocale(), columnsModel);
 
@@ -162,7 +176,22 @@ public class GTACoachedParticipantListController extends FormBasicController {
 	}
 	
 	private void updateModel() {
-		tableModel.setObjects(assessableIdentities);
+		RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry();
+		List<TaskLight> tasks = gtaManager.getTasksLight(entry, gtaNode);
+		Map<Long,TaskLight> identityToTasks = new HashMap<>();
+		for(TaskLight task:tasks) {
+			if(task.getIdentityKey() != null) {
+				identityToTasks.put(task.getIdentityKey(), task);
+			}
+		}
+		
+		List<CoachedIdentityRow> rows = new ArrayList<>(assessableIdentities.size());
+		for(UserPropertiesRow assessableIdentity:assessableIdentities) {
+			TaskLight task = identityToTasks.get(assessableIdentity.getIdentityKey());
+			rows.add(new CoachedIdentityRow(assessableIdentity, task));
+		}
+		
+		tableModel.setObjects(rows);
 		tableEl.reset();
 	}
 
@@ -177,9 +206,9 @@ public class GTACoachedParticipantListController extends FormBasicController {
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
 				String cmd = se.getCommand();
-				Identity row = tableModel.getObject(se.getIndex());
+				CoachedIdentityRow row = tableModel.getObject(se.getIndex());
 				if(StringHelper.containsNonWhitespace(cmd)) {
-					fireEvent(ureq, new SelectIdentityEvent(row));	
+					fireEvent(ureq, new SelectIdentityEvent(row.getIdentity().getIdentityKey()));	
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
index 42d13b40627b5ad4d3676c69e9d092bbefbcf676..90d92fcf1cbfc46e906b14ce8d11d014ff7e0a4c 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
@@ -32,6 +32,7 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
+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;
@@ -301,8 +302,8 @@ public class GTAParticipantController extends GTAAbstractController {
 			ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId());
 
 			for(Identity identity:identities) {
-				UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
-				gtaNode.incrementUserAttempts(userCourseEnv);
+				UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
+				gtaNode.incrementUserAttempts(uce);
 			}
 		} else {
 			gtaNode.incrementUserAttempts(userCourseEnv);
@@ -459,6 +460,9 @@ public class GTAParticipantController extends GTAAbstractController {
 				listenTo(solutionsCtrl);
 				mainVC.put("solutions", solutionsCtrl.getInitialComponent());
 			}
+		} else {
+			VelocityContainer waitVC = createVelocityContainer("wait_for_solutions");
+			mainVC.put("solutions", waitVC);
 		}
 	}
 
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java
index c0c79a17687270728a1855db663c4018381aa9b3..00af7b3c6d85f0e7840832dbf58ad417d1ec6a40 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java
@@ -303,14 +303,14 @@ public class GTAWorkflowEditController extends FormBasicController {
 		Date solutionVisibleAfter = config.getDateValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER);
 		solutionVisibleAfterEl = uifactory.addDateChooser("visibleafter", "sample.solution.visible.after", solutionVisibleAfter, stepsCont);
 		solutionVisibleAfterEl.setDateChooserTimeEnabled(true);
-		solutionVisibleAfterEl.setVisible(sample);
+		solutionVisibleAfterEl.setVisible(sample && !useRelativeDates);
 
 		//relative deadline
 		String solutionPage = velocity_root + "/solution_relative_date.html";
 		solutionVisibleRelCont = FormLayoutContainer.createCustomFormLayout("solutionRelativeDeadline", getTranslator(), solutionPage);
 		solutionVisibleRelCont.setRootForm(mainForm);
 		solutionVisibleRelCont.setLabel("sample.solution.visible.after", null);
-		solutionVisibleRelCont.setVisible(submit && useRelativeDates);
+		solutionVisibleRelCont.setVisible(sample && useRelativeDates);
 		stepsCont.add(solutionVisibleRelCont);
 		
 		numOfDays = config.getIntegerSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE, -1);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
index 24c820d830f8faa4c633a11fc53b589a751bb892..91412256b95bfe028117d18fbcfed53e0f84193c 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
@@ -336,18 +336,20 @@ public class GroupAssessmentController extends FormBasicController {
 	protected boolean validateFormLogic(UserRequest ureq) {
 		boolean allOk = true;
 
-		List<AssessmentRow> rows = model.getObjects();	
-		for(AssessmentRow row:rows) {
-			TextElement scoreEl = row.getScoreEl();
-			String value = scoreEl.getValue();
-			if(withScore && StringHelper.containsNonWhitespace(value)) {
-				try {
-					float score = Float.parseFloat(value);
-					if(score < 0.0f) {
-						//not acceptable
+		if(withScore) {
+			List<AssessmentRow> rows = model.getObjects();	
+			for(AssessmentRow row:rows) {
+				TextElement scoreEl = row.getScoreEl();
+				String value = scoreEl.getValue();
+				if(StringHelper.containsNonWhitespace(value)) {
+					try {
+						float score = Float.parseFloat(value);
+						if(score < 0.0f) {
+							//not acceptable
+						}
+					} catch (NumberFormatException e) {
+						allOk = false;
 					}
-				} catch (NumberFormatException e) {
-					allOk = false;
 				}
 			}
 		}
@@ -361,9 +363,12 @@ public class GroupAssessmentController extends FormBasicController {
 		List<AssessmentRow> rows = model.getObjects();	
 		if(applyToAllEl.isAtLeastSelected(1)) {
 			Float score = null;
-			String scoreValue = groupScoreEl.getValue();
-			if(withScore && StringHelper.containsNonWhitespace(scoreValue)) {
-				score = Float.parseFloat(scoreValue);
+			
+			if(withScore) {
+				String scoreValue = groupScoreEl.getValue();
+				if(StringHelper.containsNonWhitespace(scoreValue)) {
+					score = Float.parseFloat(scoreValue);
+				}
 			}
 			
 			Boolean passed = null;
@@ -379,10 +384,13 @@ public class GroupAssessmentController extends FormBasicController {
 		} else {
 			for(AssessmentRow row:rows) {
 				UserCourseEnvironment userCourseEnv = row.getUserCourseEnvironment();
-				String value = row.getScoreEl().getValue();
+				
 				Float score = null;
-				if(withScore && StringHelper.containsNonWhitespace(value)) {
-					score = Float.parseFloat(value);
+				if(withScore) {
+					String value = row.getScoreEl().getValue();
+					if(StringHelper.containsNonWhitespace(value)) {
+						score = Float.parseFloat(value);
+					}
 				}
 				
 				Boolean passed = null;
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/NewDocumentController.java b/src/main/java/org/olat/course/nodes/gta/ui/NewDocumentController.java
new file mode 100644
index 0000000000000000000000000000000000000000..335ef213f65d06e91637f7e91b49d0607220b1a7
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/NewDocumentController.java
@@ -0,0 +1,112 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSContainer;
+
+/**
+ * 
+ * Initial date: 13.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class NewDocumentController extends FormBasicController {
+	
+	private TextElement filenameEl;
+	private final VFSContainer documentContainer;
+	
+	public NewDocumentController(UserRequest ureq, WindowControl wControl, VFSContainer documentContainer) {
+		super(ureq, wControl);
+		this.documentContainer = documentContainer;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		filenameEl = uifactory.addTextElement("fileName", "file.name", -1, "", formLayout);
+		filenameEl.setExampleKey("file.name.example", null);
+		filenameEl.setDisplaySize(20);
+		filenameEl.setMandatory(true);
+		
+		FormLayoutContainer formButtons = FormLayoutContainer.createButtonLayout("formButton", getTranslator());
+		formLayout.add(formButtons);
+		uifactory.addFormSubmitButton("submit", "create", formButtons);
+		uifactory.addFormCancelButton("cancel", formButtons, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	public String getFilename() {
+		String value = filenameEl.getValue();
+		String lowerCased = value.toLowerCase();
+		if(!lowerCased.endsWith(".xhtm")
+				&& !lowerCased.endsWith(".html")
+				&& !lowerCased.endsWith(".htm")) {
+			value += ".html";
+		}
+		return value;
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		filenameEl.clearError();
+		String val = filenameEl.getValue();
+		if(!StringHelper.containsNonWhitespace(val)) {
+			filenameEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		} else {
+			String filename = getFilename();
+			if(documentContainer.resolve(filename) != null) {
+				filenameEl.setErrorKey("error.file.exists", null);
+				allOk &= false;
+			}else if (!FileUtils.validateFilename(filename)) {
+				filenameEl.setErrorKey("error.file.invalid", null);
+				allOk &= false;
+			}
+		}
+
+		return allOk & super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/SelectIdentityEvent.java b/src/main/java/org/olat/course/nodes/gta/ui/SelectIdentityEvent.java
index 937de4670d5fc6ce8c211747cdb3eec16262d8fb..57d6da1e1fa5c95dae35c03f0ee6c0eafcbbc017 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/SelectIdentityEvent.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/SelectIdentityEvent.java
@@ -20,7 +20,6 @@
 package org.olat.course.nodes.gta.ui;
 
 import org.olat.core.gui.control.Event;
-import org.olat.core.id.Identity;
 
 /**
  * 
@@ -31,14 +30,14 @@ import org.olat.core.id.Identity;
 public class SelectIdentityEvent extends Event {
 
 	private static final long serialVersionUID = -6380404222959527487L;
-	private final Identity identity;
+	private final Long identityKey;
 	
-	public SelectIdentityEvent(Identity identity) {
+	public SelectIdentityEvent(Long identityKey) {
 		super("select-identity");
-		this.identity = identity;
+		this.identityKey = identityKey;
 	}
 
-	public Identity getIdentity() {
-		return identity;
+	public Long getIdentityKey() {
+		return identityKey;
 	}
 }
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 626e6e0bad6ecd6905b5a492b1f7c3567fc6b412..73b802b91dcecfeb1ad0a0e72576eead0aecaa37 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
@@ -77,6 +77,7 @@ class SubmitDocumentsController extends FormBasicController {
 	private FormLink uploadDocButton, createDocButton;
 
 	private CloseableModalController cmc;
+	private NewDocumentController newDocCtrl;
 	private DocumentUploadController uploadCtrl, replaceCtrl;
 	private DialogBoxController confirmDeleteCtrl;
 	private HTMLEditorController newDocumentEditorCtrl, editDocumentEditorCtrl;
@@ -184,6 +185,15 @@ class SubmitDocumentsController extends FormBasicController {
 			}
 			cmc.deactivate();
 			cleanUp();
+		} else if(newDocCtrl == source) {
+			String filename = newDocCtrl.getFilename();
+			cmc.deactivate();
+			cleanUp();
+			
+			if(event == Event.DONE_EVENT) {
+				doCreateDocumentEditor(ureq, filename);
+				updateModel();
+			} 
 		} else if(newDocumentEditorCtrl == source) {
 			if(event == Event.DONE_EVENT) {
 				updateModel();
@@ -208,10 +218,12 @@ class SubmitDocumentsController extends FormBasicController {
 		removeAsListenerAndDispose(newDocumentEditorCtrl);
 		removeAsListenerAndDispose(confirmDeleteCtrl);
 		removeAsListenerAndDispose(uploadCtrl);
+		removeAsListenerAndDispose(newDocCtrl);
 		removeAsListenerAndDispose(cmc);
 		newDocumentEditorCtrl = null;
 		confirmDeleteCtrl = null;
 		uploadCtrl = null;
+		newDocCtrl = null;
 		cmc = null;
 	}
 
@@ -225,7 +237,7 @@ class SubmitDocumentsController extends FormBasicController {
 		if(uploadDocButton == source) {
 			doOpenDocumentUpload(ureq);
 		} else if(createDocButton == source) {
-			doCreateDocumentEditor(ureq);
+			doChooseFilename(ureq);
 		} else if(tableEl == source) {
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
@@ -315,13 +327,27 @@ class SubmitDocumentsController extends FormBasicController {
 		}
 	}
 	
-	private void doCreateDocumentEditor(UserRequest ureq) {
+	private void doChooseFilename(UserRequest ureq) {
+		if(newDocCtrl != null) return;
+		
+		if(maxDocs > 0 && maxDocs <= model.getRowCount()) {
+			showWarning("error.max.documents");
+		} else {
+			newDocCtrl = new NewDocumentController(ureq, getWindowControl(), documentsContainer);
+			listenTo(newDocCtrl);
+			
+			cmc = new CloseableModalController(getWindowControl(), "close", newDocCtrl.getInitialComponent());
+			listenTo(cmc);
+			cmc.activate();
+		}
+	}
+	
+	private void doCreateDocumentEditor(UserRequest ureq, String documentName) {
 		if(newDocumentEditorCtrl != null) return;
 		
 		if(maxDocs > 0 && maxDocs <= model.getRowCount()) {
 			showWarning("error.max.documents");
 		} else {
-			String documentName = "document.html";
 			VFSItem item = documentsContainer.resolve(documentName);
 			if(item == null) {
 				documentsContainer.createChildLeaf(documentName);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java b/src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..594faab48ff780af198c6017bb2f40b30e8d2b17
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java
@@ -0,0 +1,63 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.gta.ui;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+import org.olat.course.nodes.gta.TaskProcess;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class TaskStatusCellRenderer implements FlexiCellRenderer {
+	
+	private final Translator translator;
+	
+	public TaskStatusCellRenderer(Translator translator) {
+		this.translator = translator;
+	}
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
+			FlexiTableComponent source, URLBuilder ubu, Translator trans) {
+		if(cellValue instanceof TaskProcess) {
+			TaskProcess step = (TaskProcess)cellValue;
+			switch(step) {
+				case assignment: target.append(translator.translate("process.assignment")); break;
+				case submit: target.append(translator.translate("process.submission")); break;
+				case review: target.append(translator.translate("process.review")); break;
+				case revision: target.append(translator.translate("process.revision")); break;
+				case correction: target.append(translator.translate("process.correction")); break;
+				case solution: target.append(translator.translate("process.solution")); break;
+				case grading: target.append(translator.translate("process.grading")); break;
+				case graded: target.append(translator.translate("process.graded")); break;
+			}
+		} else if(cellValue == null) {
+			target.append(translator.translate("process.no"));
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/assigned_task.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/assigned_task.html
index 900672e4231f564d429a9df16fec1c84b72df23d..289672dbb0d1e33c5fc37500e38a6650f33a6af5 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/_content/assigned_task.html
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/assigned_task.html
@@ -1,11 +1,11 @@
+#if($message && !$message.isEmpty())
+	<div class="o_info">$r.xssScan($message)</div>
+#end
 <div>$description
 	<div class="pull-right">
 		$r.render("download.task")<br>
 		<i class="o_icon $taskCssIcon"> </i> $r.escapeHtml($taskInfo)
 	</div>
 </div>
-#if($message && !$message.isEmpty())
-	<div class="o_info">$r.xssScan($message)</div>
-#end
 <h5>$r.escapeHtml($taskName)</h5>
 <p>$r.xssScan($taskDescription)</p>
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html
index 886bc73dd8ef0dd6146ed86ce21a92e7776efefb..4faa590ed866fb7dd24e8608fd88e96131bea975 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html
@@ -19,9 +19,6 @@
 	#end
 </div>
 #end
-<div class="o_block">
-$collapse_assignement $collapse_submit $collapse_reviewAndCorrection $collapse_revision $collapse_solution $collapse_grading
-</div>
 
 <div class="o_process">
 #if($assignmentEnabled)
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/wait_for_solutions.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/wait_for_solutions.html
new file mode 100644
index 0000000000000000000000000000000000000000..0a7a05b56f17660a4dcdbd546168e29d625836a8
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/wait_for_solutions.html
@@ -0,0 +1 @@
+<div class="o_info"><i class="o_icon o_icon-lg o_icon_waiting"> </i> $r.translate("wait.for.solutions")</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties
index baf1a7fb5d8d634f327274ee315673d50c6b2ba3..ffbf00aa160e3653e316066ec9cb27125bcb282e 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties
@@ -4,8 +4,8 @@ add.task=Aufgabe hinzuf\u00FCgen
 assessment.group.tool=Gruppe bewerten
 assignment.config.title=Aufgabe zuweisen
 assignment.deadline=Zuweisungstermin
-before=Vor
-bulk.download.title=Alle abgegebene Dokumenten herunterladen
+before=vorher
+bulk.download.title=Alle abgegebenen Dokumente herunterladen
 bulk.review=Beurteilung herunterladen
 bulk.solutions=Musterl\u00F6sungen herunterladen
 bulk.submitted.documents=Abgegebene Dokumente
@@ -21,7 +21,7 @@ coach.corrections.description=Sie haben folgende Korrekturen zur\u00FCckgegeben.
 coach.documents.successfully.reviewed=Begutachtet\!
 coach.need.revision.button=Ben\u00F6tigt \u00DCberarbeitung
 coach.reviewed.button=Begutachtet
-coach.revisions.description=Sie haben die folgenden Dokumente \u00FCberarbeitet.
+coach.revisions.description=Sie haben die folgenden \u00FCberarbeiteten Dokumente erhalten.
 coach.submit.corrections.to.revision.button=Korrekturen absenden
 coach.submitted.documents.description=Diese Dokumente wurden abgegeben.
 coach.task.assigned.description=Die folgende Aufgabe wurde zugewiesen
@@ -31,6 +31,7 @@ condition.accessibility.title=Zugang
 confirm.delete.solution.description=Wollen Sie wirklich die L\u00F6sung "{0}" l\u00F6schen?
 confirm.delete.solution.title=L\u00F6sung l\u00F6schen
 confirmation.title=Abgabe Best\u00E4tigung
+create=Erstellen
 create.areas=Lernbereich erstellen
 create.groups=Gruppe erstellen
 days.after=Tage nach
@@ -46,6 +47,8 @@ error.assignment.closed=Zuweisung ist geschlossen.
 error.duplicate.coaching=Der Teilnehmer ist Teilnehmer von mehreren Gruppen f\u00FCr diese Aufgabe.
 error.duplicate.memberships=Die folgenden Teilnehmer sind Mitglieder von mehreren Gruppen\: {1}
 error.editor.atLeastOne=Sie m\u00FCssen mindestens einen Editortyp w\u00E4hlen.
+error.file.exists=$org.olat.core.commons.modules.bc\:cfile.already.exists
+error.file.invalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid
 error.max.documents=Sie d\u00FCrfen nicht mehr als <b>{0}</b> Dokument(e) abgeben. Aber sie k\u00F6nnen noch ein Dokument austauschen oder editieren.
 error.missing.group=Sie haben noch keine Gruppe gew\u00E4hlt
 error.missing.score.config=Fehlende Bewertungskonfiguration
@@ -58,9 +61,11 @@ error.not.member.title=Reserviert f\u00FCr die Teilnehmer der Aufgabe
 error.number.format=Geben Sie eine Zahl zwischen 1 und 12 ein oder lassen Sie das Feld leer.
 error.select.atleastonestep=Sie haben keine Schritte gew\u00E4hlt
 external.editor=Abgabe mit internem Texteditor
+file.name=Dateiname
+file.name.example=Document.html
 grading=Bewertung
 group.apply.toall=F\u00FCr die ganze Gruppe
-group.passed=Gruppe bestanden/nicht bestanden
+group.passed=Gruppe bestanden
 group.score=Gruppe Punkte
 group.title=Leistungs\u00FCbersicht
 info.title=$org.olat.course.nodes.ms\:info.title
@@ -75,7 +80,7 @@ notifications.revision.individual=Neue \u00DCberarbeitungen "{0}" von "{1}"
 notifications.solution=Neue Musterl\u00F6sung "{0}"
 notifications.submission.group=Neue abgegebene Dokumente "{0}" von "{2}" f\u00FCr Gruppe "{1}" hochgeladen
 notifications.submission.individual=Neue abgegebene Dokumente "{0}" von "{1}"
-open.editor=L\u00F6sung bearbeiten
+open.editor=L\u00F6sung erstellen
 open.group=Gruppe \u00F6ffnen
 pane.tab.accessibility=Zugang
 pane.tab.assignment=Zuweisung
@@ -86,10 +91,19 @@ pane.tab.workflow=Workflow
 preview=$org.olat.course.nodes.ta\:form.task.preview
 preview.disabled=$org.olat.course.nodes.ta\:form.task.without.preview
 preview.enabled=$org.olat.course.nodes.ta\:form.task.with.preview
-relative.dates=Relative Datum
+process.no=Zuweisung
+process.assignment=Zuweisung
+process.submission=Abgabe
+process.review=\u00DCberarbeitung
+process.revision=\u00DCberarbeitung
+process.correction=Korrektur
+process.solution=L\u00F6sung
+process.grading=Bewertung
+process.graded=Bewertet
+relative.dates=Relatives Datum
 relative.to.course.start=Kurs Beginn
-relative.to.course.launch=Kurs erstes Besuch
-relative.to.enrollment=Enrollment
+relative.to.course.launch=Erster Kursbesuch
+relative.to.enrollment=Einschreibung
 replace=Austauschen
 replace.document=Dokument austauschen
 review.and.correction=\u00DCberarbeitung und Korrektur
@@ -99,6 +113,7 @@ revision.period=\u00DCberarbeitungsperiode
 run.assignment.due.date=Zuweisung Termin\: {0}
 run.assignment.title=Aufgabe Zuweisung
 run.coach=Korrigieren
+run.coach.corrections.description=Sie haben die folgende Korrekturanforderung erstellt.
 run.corrections.description=Ihr Betreuer hat folgende Dokumente f\u00FCr Sie hinzugef\u00FCgt\:
 run.documents.successfully.submitted=Ihr(e) Dokument(e) wurden erfolgreich eingereicht.
 run.grading=Bewertung
@@ -116,7 +131,7 @@ run.solution.available.date={0}
 run.solutions.description=Hier finden Sie die von Ihrem Betreuer zur Verf\u00FCgung gestellten Musterl\u00F6sungen.
 run.submit=Abgabe
 run.submit.button=Endg\u00FCltige Abgabe
-run.submit.confirm=Das Abgabe von dem Aufgabe ist endg\u00FCltig.
+run.submit.confirm=Die Abgabe der Aufgabe ist endg\u00FCltig.
 run.submit.confirm.group=$\:run.submit.confirm<br/>Dies ist eine Gruppenaufgabe\! Die hier getroffene Auswahl ist f\u00FCr alle Mitglieder der Gruppe "{0}" g\u00FCltig\!
 run.submit.due.date=Abgabe Termin\: {0}
 run.submit.individual.description.all=Geben Sie Ihre L\u00F6sung ab indem Sie entweder ein Dokument hochladen oder den hier verf\u00FCgbaren Editor benutzen.
@@ -146,6 +161,7 @@ table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta
 table.header.group.name=Gruppe
 table.header.passed=Bestanden
 table.header.score=Punkte
+table.header.group.step=Schritt
 task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen
 task.assigned.description=Die folgende Aufgabe wurde Ihnen zugewiesen\:
 task.assignment=Zuweisung
@@ -162,12 +178,13 @@ task.list.description=Ausw\u00E4hlen...
 task.list.title=Aufgaben
 task.steps.description=W\u00E4hlen Sie welche Elemente f\u00FCr den Workflow aktiviert werden sollen und geben Sie optional die dazugeh\u00F6rigen F\u00E4lligkeitsdaten f\u00FCr das Workflow-Management ein.
 task.steps.title=Abschnitte
-task.successfully.assigned=Aufgabe erfolgreich zugwiesen.
+task.successfully.assigned=Aufgabe erfolgreich zugewiesen.
 task.text=$org.olat.course.nodes.ta\:form.task.text
 task.title=Titel
 task.type.description=Wenn die Gruppenaufgabe aktiviert ist, werden alle Abschnitte des Workflows als Gruppe und nicht als Einzelperson ausgef\u00FChrt.
 task.type.title=Aufgabentyp
 upload.document=Dokument hochladen
+wait.for.solutions=Die Musterl\u00F6sung wird zum angegebenen Zeitpunkt freigegeben.
 warning.group.pick.task=Dies ist eine Gruppenaufgabe\! Die hier getroffene Auswahl ist f\u00FCr alle Mitglieder der Gruppe "{0}" g\u00FCltig\! Stellen Sie sicher dass diese Auswahl zuvor innerhalb Ihrer Gruppe diskutiert wurde\! Nur ein Gruppenmitglied kann die Gruppenaufgabe ausw\u00E4len.
 warning.group.submit=Dies ist eine Gruppenaufgabe\! Das abgegebene Dokument ist f\u00FCr alle Mitglieder der Gruppe "{0}" g\u00FCltig\! Stellen Sie sicher dass diese L\u00F6sung zuvor innerhalb  Ihrer Gruppe diskutiert wurde\! Nur ein Gruppenmitglied kann eine L\u00F6sung im Namen aller Gruppenmitglieder abgeben.
 warning.group.task=Dies ist eine Gruppenaufgabe\! Aufgbabenzuweisung, Abgabe sowie die Bewertung werden f\u00FCr die Gruppe vorgenommen. Besprechen Sie mit den anderen Teilnehmern ihrer Gruppe wie sie gemeinsam die Aufgabe ausw\u00E4hlen und bearbeiten wollen.
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties
index ecb811532129fb2027dc0cc7893d6d00d679001f..2a277c9ebad1bbddc7624665f74cfd0f86798e3b 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties
@@ -4,15 +4,15 @@ add.task=Add task
 assessment.group.tool=Grade group
 assignment.config.title=Task assignment configuration
 assignment.deadline=Assignment deadline
-before=Before
+before=beforehand
 bulk.download.title=Download all submitted files
 bulk.review=Download review
 bulk.solutions=Download solutions
 bulk.submitted.documents=Download submitted documents
 change.group=Change active group
 change.group.description=You are participating in multiple groups.
-choose.areas=Selected areas
-choose.groups=Selected groups
+choose.areas=Select areas
+choose.groups=Select groups
 choosed.areas=Areas
 choosed.groups=Groups
 coach.assessment=Grade
@@ -21,7 +21,7 @@ coach.corrections.description=You have returned the following revisions
 coach.documents.successfully.reviewed=Reviewed\!
 coach.need.revision.button=Needs revision
 coach.reviewed.button=Reviewed
-coach.revisions.description=You have reviewed the following documents
+coach.revisions.description=You have received the following revised documents
 coach.submit.corrections.to.revision.button=Send revisions
 coach.submitted.documents.description=These documents have been submitted
 coach.task.assigned.description=The following task has been assigned
@@ -31,6 +31,7 @@ condition.accessibility.title=Access
 confirm.delete.solution.description=Do you want to delete the solution "{0}"?
 confirm.delete.solution.title=Delete submitted solution 
 confirmation.title=Submit confirmation
+create=Create
 create.areas=Create learning area
 create.groups=Create group
 days.after=Days after
@@ -46,6 +47,8 @@ error.assignment.closed=Assignment is closed
 error.duplicate.coaching=This user is a member of multiple groups in this task.
 error.duplicate.memberships=The following users are members of multiple groups\: {1}
 error.editor.atLeastOne=You must choose at least one kind of editor.
+error.file.exists=$org.olat.core.commons.modules.bc\:cfile.already.exists
+error.file.invalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid
 error.max.documents=You are not allowed to submit more than <b>{0}</b> Documents. You may edit or change a document.
 error.missing.group=You have not selected a group yet
 error.missing.score.config=Missing score configuration
@@ -58,9 +61,11 @@ error.not.member.title=Reserved for task members
 error.number.format=Enter a number between 1 and 12 or leave the field blank.
 error.select.atleastonestep=You have not selected any steps
 external.editor=Submit with embedded text editor
+file.name=File name
+file.name.example=Document.html
 grading=Grading
 group.apply.toall=For the whole group
-group.passed=Groups passed/failed
+group.passed=Group passed
 group.score=Group score
 group.title=Score summary
 info.title=$org.olat.course.nodes.ms\:info.title
@@ -86,8 +91,17 @@ pane.tab.workflow=Workflow
 preview=$org.olat.course.nodes.ta\:form.task.preview
 preview.disabled=$org.olat.course.nodes.ta\:form.task.without.preview
 preview.enabled=$org.olat.course.nodes.ta\:form.task.with.preview
+process.no=Assignment
+process.assignment=Assignment
+process.submission=Submission
+process.review=Review
+process.revision=Revision
+process.correction=Correction
+process.solution=Solution
+process.grading=Grading
+process.graded=Graded
 relative.dates=Relative dates
-relative.to.course.start=Course begin
+relative.to.course.start=Course start
 relative.to.course.launch=Course first launch
 relative.to.enrollment=Enrollment
 replace=Replace
@@ -99,6 +113,7 @@ revision.period=Revision period
 run.assignment.due.date=Due date\: {0}
 run.assignment.title=Task assignment
 run.coach=Correct
+run.coach.corrections.description=You have set the following correction request.
 run.corrections.description=Your coach attached the following files for you\:
 run.documents.successfully.submitted=Your document(s) have been successfully submitted.
 run.grading=Grading
@@ -146,6 +161,7 @@ table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta
 table.header.group.name=Group
 table.header.passed=Passed
 table.header.score=Points
+table.header.group.step=Step
 task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen
 task.assigned.description=The following task has been assigned to you\:
 task.assignment=Task assignment
@@ -168,6 +184,7 @@ task.title=Title
 task.type.description=When group task is enabled, all steps of the workflow are executed as a group and not as an individual.
 task.type.title=Task type
 upload.document=Upload document
+wait.for.solutions=The sample solution will be displayed at the date specified above.
 warning.group.pick.task=This is a group task\! The selection made here is valid for all members of the group "{0}"\! Make sure you discussed this selection within the group prior to selecting a task\! Only one member of the group can select the task for the group.
 warning.group.submit=This is a group task\! The submitted document is valid for all members of the group "{0}"\! Make sure you discussed this solution document prior to uploading it here\! Only one member of the group can submit a solution on behalf of all group members.
 warning.group.task=This is a group task\! The task assignment, submission of documents and grading are performed as a group. Contact your group peers on how to proceed on deciding for a task and to collaboratively solve the task.
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectDetailsDisplayController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectDetailsDisplayController.java
index 03818027f086081cae5d1a620d6025a67e672d1e..656825d21e8137953d89a12099f048bd9f2ad57b 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectDetailsDisplayController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectDetailsDisplayController.java
@@ -182,7 +182,7 @@ public class ProjectDetailsDisplayController extends BasicController {
 		if (project.getMaxMembers() == Project.MAX_MEMBERS_UNLIMITED) {
 			myContent.contextPut("projectPlaces", this.getTranslator().translate("detailsform.unlimited.project.members") );
 		} else {
-			String placesValue = projectBrokerManager.getSelectedPlaces(project) + " " + this.getTranslator().translate("detailsform.places.of") + " " + project.getMaxMembers();
+			String placesValue = project.getSelectedPlaces() + " " + this.getTranslator().translate("detailsform.places.of") + " " + project.getMaxMembers();
 			myContent.contextPut("projectPlaces", placesValue);
 		}
 		
@@ -226,6 +226,7 @@ public class ProjectDetailsDisplayController extends BasicController {
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
 	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if ( projectBrokerManager.existsProject(project.getKey()) ) {
 			if (source == editProjectButton) {
@@ -244,8 +245,9 @@ public class ProjectDetailsDisplayController extends BasicController {
 					Link projectLeaderLink = (Link)source;
 					final Identity identity = (Identity)projectLeaderLink.getUserObject();
 					ControllerCreator ctrlCreator = new ControllerCreator() {
+						@Override
 						public Controller createController(UserRequest lureq, WindowControl lwControl) {
-							return new UserInfoMainController(lureq, lwControl, identity);
+							return new UserInfoMainController(lureq, lwControl, identity, true, false);
 						}
 					};
 					// wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
index 77a3f57881332ca5905a3f2ce25ad22681c04b86..93c88eb8e505fcda0532f7493d5560a96ac8e8e5 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
@@ -195,9 +195,9 @@ public class ProjectListController extends BasicController implements GenericEve
 			if (resId.longValue() != 0) {
 				if (isLogDebugEnabled()) logDebug("projectId=" , ores.getResourceableId().toString());
 				
-				Project currentProject = projectBrokerManager.getProject(ores.getResourceableId());
-				if (currentProject != null) {
-					activateProjectController(currentProject, ureq);				
+				Project proj = projectBrokerManager.getProject(ores.getResourceableId());
+				if (proj != null) {
+					activateProjectController(proj, ureq);				
 				} else {
 					// message not found, do nothing. Load normal start screen
 					logDebug("Invalid projectId=" , ores.getResourceableId().toString());
@@ -281,23 +281,23 @@ public class ProjectListController extends BasicController implements GenericEve
 	}
 
 
-	private void handleTableEventForProject(UserRequest urequest, TableEvent te, Project currentProject) {
+	private void handleTableEventForProject(UserRequest urequest, TableEvent te, Project selectedProject) {
 		if ( te.getActionId().equals(TABLE_ACTION_SHOW_DETAIL)) {
-			activateProjectController(currentProject, urequest);
+			activateProjectController(selectedProject, urequest);
 		} else if ( te.getActionId().equals(TABLE_ACTION_ACCOUNT_MANAGER)) {
-			activateUserController(currentProject, urequest, te);
+			activateUserController(selectedProject, urequest, te);
 		} else if ( te.getActionId().equals(TABLE_ACTION_SELECT)) {
-			if(!projectGroupManager.isDeselectionAllowed(currentProject)){
+			if(!projectGroupManager.isDeselectionAllowed(selectedProject)){
 				List<String> warningButtons = new ArrayList<String>();
 				warningButtons.add(translate("info.projectbroker.no.deselect.select"));
 				warningButtons.add(translate("info.projectbroker.no.deselect.cancel"));
-				String message = translate("info.projectbroker.deselect.confirmation",currentProject.getTitle())+"<br/><div class=\"o_important\">"+translate("info.projectbroker.no.deselect")+"</div>"; 
+				String message = translate("info.projectbroker.deselect.confirmation",selectedProject.getTitle())+"<br/><div class=\"o_important\">"+translate("info.projectbroker.no.deselect")+"</div>"; 
 				noDeselectWarning = activateGenericDialog(urequest, translate("info.projectbroker.no.deselect.title"), message, warningButtons, noDeselectWarning);
 				return;
 			}
-			handleEnrollAction(urequest, currentProject);
+			handleEnrollAction(urequest, selectedProject);
 		} else if ( te.getActionId().equals(TABLE_ACTION_CANCEL_SELECT)) {
-			handleCancelEnrollmentAction(urequest, currentProject);
+			handleCancelEnrollmentAction(urequest, selectedProject);
 		} else {
 			getLogger().warn("Controller-event-handling: Unkown event=" + te);
 		}
@@ -305,15 +305,15 @@ public class ProjectListController extends BasicController implements GenericEve
 	}
 
 
-	private void handleCancelEnrollmentAction(UserRequest urequest, Project currentProject) {
-		getLogger().debug("start cancelProjectEnrollmentOf identity=" + urequest.getIdentity() + " to project=" + currentProject);
-		boolean cancelledEnrollmend = projectBrokerManager.cancelProjectEnrollmentOf(urequest.getIdentity(), currentProject, moduleConfig);
+	private void handleCancelEnrollmentAction(UserRequest urequest, Project selectedProject) {
+		getLogger().debug("start cancelProjectEnrollmentOf identity=" + urequest.getIdentity() + " to project=" + selectedProject);
+		boolean cancelledEnrollmend = projectBrokerManager.cancelProjectEnrollmentOf(urequest.getIdentity(), selectedProject, moduleConfig);
 		if (cancelledEnrollmend) {
-			projectBrokerMailer.sendCancelEnrollmentEmailToParticipant(urequest.getIdentity(), currentProject, this.getTranslator());
-			if (currentProject.isMailNotificationEnabled()) {
-				projectBrokerMailer.sendCancelEnrollmentEmailToManager(urequest.getIdentity(), currentProject, this.getTranslator());
+			projectBrokerMailer.sendCancelEnrollmentEmailToParticipant(urequest.getIdentity(), selectedProject, this.getTranslator());
+			if (selectedProject.isMailNotificationEnabled()) {
+				projectBrokerMailer.sendCancelEnrollmentEmailToManager(urequest.getIdentity(), selectedProject, this.getTranslator());
 			}
-			projectGroupManager.sendGroupChangeEvent(currentProject, courseId, urequest.getIdentity());
+			projectGroupManager.sendGroupChangeEvent(selectedProject, courseId, urequest.getIdentity());
 		} else {
 			showInfo("info.msg.could.not.cancel.enrollment");
 		}
@@ -321,15 +321,15 @@ public class ProjectListController extends BasicController implements GenericEve
 	}
 
 
-	private void handleEnrollAction(UserRequest urequest, Project currentProject) {
-		getLogger().debug("start enrollProjectParticipant identity=" + urequest.getIdentity() + " to project=" + currentProject);
-		boolean enrolled = projectBrokerManager.enrollProjectParticipant(urequest.getIdentity(), currentProject, moduleConfig, nbrSelectedProjects, isParticipantInAnyProject);
+	private void handleEnrollAction(UserRequest urequest, Project selectedProject) {
+		getLogger().debug("start enrollProjectParticipant identity=" + urequest.getIdentity() + " to project=" + selectedProject);
+		boolean enrolled = projectBrokerManager.enrollProjectParticipant(urequest.getIdentity(), selectedProject, moduleConfig, nbrSelectedProjects, isParticipantInAnyProject);
 		if (enrolled) {
-			projectBrokerMailer.sendEnrolledEmailToParticipant(urequest.getIdentity(), currentProject, this.getTranslator());
-			if (currentProject.isMailNotificationEnabled()) {
-				projectBrokerMailer.sendEnrolledEmailToManager(urequest.getIdentity(), currentProject, this.getTranslator());
+			projectBrokerMailer.sendEnrolledEmailToParticipant(urequest.getIdentity(), selectedProject, this.getTranslator());
+			if (selectedProject.isMailNotificationEnabled()) {
+				projectBrokerMailer.sendEnrolledEmailToManager(urequest.getIdentity(), selectedProject, this.getTranslator());
 			}
-			projectGroupManager.sendGroupChangeEvent(currentProject, courseId, urequest.getIdentity());
+			projectGroupManager.sendGroupChangeEvent(selectedProject, courseId, urequest.getIdentity());
 		} else {
 			showInfo("info.msg.could.not.enroll");
 		}
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListTableModel.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListTableModel.java
index 4400036d4516075267d6b15222c1e7b2a6d7d68e..1801099eb06f1b7522fc7bad30703a111b4ee8ce 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListTableModel.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListTableModel.java
@@ -101,10 +101,10 @@ public class ProjectListTableModel extends DefaultTableDataModel<Project> {
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
 	 */
+	@Override
 	public Object getValueAt(int row, int col) {
 		Project project = objects.get(row);
 		if (col == 0) {
-			log.debug("project=" + project); // debug-output only once for each project
 			String name = project.getTitle();
 			return name;
 		} else if (col == 1) {
@@ -123,7 +123,7 @@ public class ProjectListTableModel extends DefaultTableDataModel<Project> {
 			}
 		} else if (col == (numberOfCustomFieldInTable + numberOfEventInTable + 2)) {
 			return projectBrokerManager.getStateFor(project,identity,moduleConfig);
-		} else if (col == (numberOfCustomFieldInTable + numberOfEventInTable + 3)) {
+		} else if (col == (numberOfCustomFieldInTable + numberOfEventInTable + 3)) { // num. of slots
 			StringBuilder buf = new StringBuilder();
 			buf.append(project.getSelectedPlaces());
 			if (project.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) {
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/datamodel/ProjectImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/datamodel/ProjectImpl.java
index 719cf44e20e7e83131164847bc07bc0d6b90d760..54a6582cc289eecddd64ab4567534d17ad488e01 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/datamodel/ProjectImpl.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/datamodel/ProjectImpl.java
@@ -42,6 +42,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
+import org.olat.resource.accesscontrol.manager.ACReservationDAO;
 
 
 /**
@@ -142,8 +143,10 @@ public class ProjectImpl extends PersistentObject implements Project {
 	}
 
 	public int getSelectedPlaces() {
-		return CoreSpringFactory.getImpl(BusinessGroupService.class).countMembers(getProjectGroup(), GroupRoles.participant.name()) +
-		                     BaseSecurityManager.getInstance().countIdentitiesOfSecurityGroup(getCandidateGroup());
+		int numOfParticipants = CoreSpringFactory.getImpl(BusinessGroupService.class).countMembers(getProjectGroup(), GroupRoles.participant.name());
+		int numOfCandidates = BaseSecurityManager.getInstance().countIdentitiesOfSecurityGroup(getCandidateGroup());
+		int numOfReservations = CoreSpringFactory.getImpl(ACReservationDAO.class).countReservations(getProjectGroup().getResource());
+		return numOfParticipants + numOfCandidates + numOfReservations;                     
 	}
 
 	public int getMaxMembers() {
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java
index b4ed194e6b446757cdbc1d8158456e3b4a025080..e55acf81f0a3b83a27cb3359ce144ea08749b75a 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java
@@ -56,13 +56,6 @@ public interface ProjectBrokerManager {
 	 */
 	public ProjectBroker getProjectBroker(Long projectBrokerId);
 	
-	/**
-	 * Get number of selected places for certain project.
-	 * @param project
-	 * @return
-	 */
-	public int getSelectedPlaces(Project project);
-	
 	/**
 	 * Creates a new project-broker and save it. 
 	 * @return
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManagerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManagerImpl.java
index cee8561f7be382911c94c04afa365f6387487266..61f3d27af355761915be330491e90db879c2bf86 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManagerImpl.java
@@ -96,7 +96,6 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 	protected ProjectBrokerManagerImpl() {
 		// cache name should not be too long e.g. 'projectbroker' is too long, use 'pb' instead.
 		projectCache = CoordinatorManager.getInstance().getCoordinator().getCacher().getCache(ProjectBrokerManager.class.getSimpleName(), "pb");
-		logDebug("ProjectBrokerManagerImpl created");
 	}
 
 	/**
@@ -104,9 +103,11 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 	 * @return List of projects for certain project-broker
 	 */
 	public List<Project> getProjectListBy(final Long projectBrokerId) {
-		logDebug("getProjectListBy for projectBroker=" + projectBrokerId);
+		final boolean debug = isLogDebugEnabled();
+
 		long rstart = 0;
-		if(isLogDebugEnabled()){
+		if(debug){
+			logDebug("getProjectListBy for projectBroker=" + projectBrokerId);
 			rstart = System.currentTimeMillis();
 		}
 		OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
@@ -118,7 +119,7 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 
 		});
 	
-		if(isLogDebugEnabled()){
+		if(debug){
 			long rstop = System.currentTimeMillis();
 			logDebug("time to fetch project with projectbroker_id " + projectBrokerId + " :" + (rstop - rstart), null);
 		}
@@ -146,49 +147,54 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 		});	
 		return project;
 	}
-
-	public int getSelectedPlaces(Project project) {
-		return businessGroupService.countMembers(project.getProjectGroup(), GroupRoles.participant.name()) +
-		       securityManager.countIdentitiesOfSecurityGroup(project.getCandidateGroup());
-	}
-
-
+	
+	@Override
 	public void updateProject(final Project project) {
 		final Long projectBrokerId = project.getProjectBroker().getKey();
 		OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
 		CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
+			@Override
 			public void execute() {
 				updateProjectAndInvalidateCache(project);
 			}
 		});	
 	}
 	
+	@Override
 	public boolean existsProject(Long projectKey) {
 		return dbInstance.findObject(ProjectImpl.class, projectKey) != null;
 	}
 
+	@Override
 	public boolean enrollProjectParticipant(final Identity identity, final Project project, final ProjectBrokerModuleConfiguration moduleConfig, final int nbrSelectedProjects, final boolean isParticipantInAnyProject) {
+		final boolean debug = isLogDebugEnabled();
+		
 		OLATResourceable projectOres = OresHelper.createOLATResourceableInstance(Project.class, project.getKey());
 		logDebug("enrollProjectParticipant: start identity=" + identity + "  project=" + project);
-		Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(projectOres, new SyncerCallback<Boolean>(){
+		Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(projectOres, new SyncerCallback<Boolean>() {
+			@Override
 			public Boolean execute() {
 				if ( existsProject( project.getKey() ) ) {
 					// For cluster-safe : reload project object here another node might have changed this in the meantime
 					Project reloadedProject = (Project) dbInstance.loadObject(project, true);					
-					logDebug("enrollProjectParticipant: project.getMaxMembers()=" + reloadedProject.getMaxMembers());
-					logDebug("enrollProjectParticipant: project.getSelectedPlaces()=" + reloadedProject.getSelectedPlaces());
+					
+					if(debug) {
+						logDebug("enrollProjectParticipant: project.getMaxMembers()=" + reloadedProject.getMaxMembers());
+						logDebug("enrollProjectParticipant: project.getSelectedPlaces()=" + reloadedProject.getSelectedPlaces());
+					}
+
 					if (canBeProjectSelectedBy(identity, reloadedProject, moduleConfig, nbrSelectedProjects, isParticipantInAnyProject) ) {				
 						
 						if (moduleConfig.isAcceptSelectionManually() ) {
 							securityManager.addIdentityToSecurityGroup(identity, reloadedProject.getCandidateGroup());
 							logAudit("ProjectBroker: Add as candidate identity=" + identity + " to project=" + reloadedProject);
-							if (isLogDebugEnabled()) {
+							if (debug) {
 								logDebug("ProjectBroker: Add as candidate reloadedProject=" + reloadedProject + "  CandidateGroup=" + reloadedProject.getCandidateGroup() );
 							}
 						} else {
 							businessGroupRelationDao.addRole(identity, reloadedProject.getProjectGroup(), GroupRoles.participant.name());
 							logAudit("ProjectBroker: Add as participant identity=" + identity + " to project=" + reloadedProject);
-							if (isLogDebugEnabled()) {
+							if (debug) {
 								logDebug("ProjectBroker: Add as participant reloadedProject=" + reloadedProject + "  ParticipantGroup=" + reloadedProject.getProjectGroup() );
 							}
 							if ( (reloadedProject.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (reloadedProject.getSelectedPlaces() >= reloadedProject.getMaxMembers()) ) {
@@ -198,7 +204,9 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 						}
 						return Boolean.TRUE;
 					} else {
-						logDebug("ProjectBroker: project-group was full for identity=" + identity + " , project=" + reloadedProject);
+						if(debug) {
+							logDebug("ProjectBroker: project-group was full for identity=" + identity + " , project=" + reloadedProject);
+						}
 						return Boolean.FALSE;
 					}
 				} else {
@@ -300,8 +308,7 @@ public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBro
 			return false;
 		}
 		// 2. check number of max project members
-		int projectMembers = businessGroupService.countMembers(project.getProjectGroup(), GroupRoles.participant.name()) +
-		                     securityManager.countIdentitiesOfSecurityGroup(project.getCandidateGroup());
+		int projectMembers = project.getSelectedPlaces();
 		if ( (project.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (projectMembers >= project.getMaxMembers()) ) {
 			logDebug("canBeSelectedBy: return false because projectMembers >= getMaxMembers()");
 			return false;
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java
index e7a9a3207c88c8299bb8e1fb744060a6e2874e43..2ccf3ded83987bd842ded0ac040dfb62a30c52b5 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java
@@ -127,15 +127,15 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou
 	}
 
 	public boolean isAccountManager(Identity identity, CoursePropertyManager cpm, CourseNode courseNode) {
-  	Property accountManagerGroupProperty = cpm.findCourseNodeProperty(courseNode, null, null, ProjectBrokerCourseNode.CONF_ACCOUNTMANAGER_GROUP_KEY);
-  	if (accountManagerGroupProperty != null) {
-  	 	Long groupKey = accountManagerGroupProperty.getLongValue();
-  		BusinessGroup accountManagerGroup = businessGroupService.loadBusinessGroup(groupKey);
-  		if (accountManagerGroup != null) {
-  			return isAccountManager(identity,  accountManagerGroup);
-  		}
-  	}
-  	return false;
+		Property accountManagerGroupProperty = cpm.findCourseNodeProperty(courseNode, null, null, ProjectBrokerCourseNode.CONF_ACCOUNTMANAGER_GROUP_KEY);
+		if (accountManagerGroupProperty != null) {
+			Long groupKey = accountManagerGroupProperty.getLongValue();
+			BusinessGroup accountManagerGroup = businessGroupService.loadBusinessGroup(groupKey);
+			if (accountManagerGroup != null) {
+				return isAccountManager(identity,  accountManagerGroup);
+			}
+		}
+		return false;
  	}
 
 	public void deleteAccountManagerGroup( CoursePropertyManager cpm, CourseNode courseNode) {
@@ -218,16 +218,16 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou
 	//TODO gsync
 		List<Identity> addedIdentities = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(project.getProjectGroup(), new SyncerCallback<List<Identity>>(){
 			public List<Identity> execute() {
-				List<Identity> addedIdentities = new ArrayList<Identity>();
+				List<Identity> addedIdentityList = new ArrayList<Identity>();
 				for (Identity identity : addIdentities) {
 					if (!securityManager.isIdentityInSecurityGroup(identity, project.getCandidateGroup()) ) {
 						securityManager.addIdentityToSecurityGroup(identity, project.getCandidateGroup());
-						addedIdentities.add(identity);
+						addedIdentityList.add(identity);
 						logAudit("ProjectBroker: Add user as candidate, identity=" + identity);
 					}
 					// fireEvents ?
 				}
-				return addedIdentities;
+				return addedIdentityList;
 			}
 		});// end of doInSync
 		return addedIdentities;
@@ -252,15 +252,15 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou
 	public BusinessGroupAddResponse acceptCandidates(final List<Identity> identities, final Project project, final Identity actionIdentity, final boolean autoSignOut, final boolean isAcceptSelectionManually) {
 		final Project reloadedProject = (Project) dbInstance.loadObject(project, true);
 		final BusinessGroupAddResponse response = new BusinessGroupAddResponse();
-		final BusinessGroupService bgs = businessGroupService;
-		BusinessGroupAddResponse state = bgs.addParticipants(actionIdentity, null, identities, reloadedProject.getProjectGroup(), null);
+		BusinessGroupAddResponse state = businessGroupService.addParticipants(actionIdentity, null, identities, reloadedProject.getProjectGroup(), null);
 		response.getAddedIdentities().addAll(state.getAddedIdentities());
 		response.getIdentitiesAlreadyInGroup().addAll(state.getAddedIdentities());
 		
 		Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(project.getProjectGroup(), new SyncerCallback<Boolean>(){
+			@Override
 			public Boolean execute() {
 				for (final Identity identity : identities) {
-					if (!bgs.hasRoles(identity, reloadedProject.getProjectGroup(), GroupRoles.participant.name())) {
+					if (!businessGroupService.hasRoles(identity, reloadedProject.getProjectGroup(), GroupRoles.participant.name())) {
 						securityManager.removeIdentityFromSecurityGroup(identity, reloadedProject.getCandidateGroup());
 						logAudit("ProjectBroker: Accept candidate, identity=" + identity + " project=" + reloadedProject);
 					}		
diff --git a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties
index 27235d3699c2e3490f2ab992e10bdbdc6a80e4a2..88a5fb2b31777b40c258e04bff1c0c675a9c2edb 100644
--- a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties
@@ -4,7 +4,7 @@ assessable.label=Transfer score from SCORM
 assessable.type.none=Don't transfer scoring information
 assessable.type.passed=Transfer passed value
 assessable.type.score=Transfer score value
-attempts.depends.label=Count attempts only if score is transfered
+attempts.depends.label=Count attempts only if score is transferred
 attempts.label=Max number of attempts
 attempts.max.reached=Maximum number of attempts are reached.
 attempts.noLimit=unlimited
diff --git a/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
index ee603df759c62b513290b61be0034723553992bf..bc7d744c91d7a35ea2676d40a19933806cf6f5e9 100644
--- a/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.olat.core.id.Identity;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.reminder.manager.ReminderRuleDAO;
 import org.olat.course.reminder.ui.AttemptsRuleEditor;
@@ -63,6 +64,12 @@ public class AttemptsRuleSPI implements FilterRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new AttemptsRuleEditor(rule, entry);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		//the node ident must be the same
+		return rule.clone();
+	}
 
 	@Override
 	public void filter(RepositoryEntry entry, List<Identity> identities, ReminderRule rule) {
diff --git a/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
index aa0645bde879a5e11187db3cbc5f3f9a26d29aff..eb8c5e1640c093454899af23267a1fa761d60b9d 100644
--- a/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.olat.core.id.Identity;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.reminder.manager.ReminderRuleDAO;
 import org.olat.course.reminder.ui.InitialAttemptsRuleEditor;
@@ -63,6 +64,11 @@ public class InitialAttemptsRuleSPI extends AbstractLaunchDateRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new InitialAttemptsRuleEditor(rule, entry);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	protected Map<Long, Date> getLaunchDates(ReminderRule rule, RepositoryEntry entry, List<Identity> identities) {
diff --git a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
index 49672fdb5266f8f9990b02fb9477dfe950f39f10..d365bbe40e0a5a475e85b5d2e59fb47abbb059f6 100644
--- a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.olat.core.id.Identity;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.reminder.manager.ReminderRuleDAO;
 import org.olat.course.reminder.ui.PassedRuleEditor;
@@ -63,6 +64,11 @@ public class PassedRuleSPI implements FilterRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new PassedRuleEditor(rule, entry);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	public void filter(RepositoryEntry entry, List<Identity> identities, ReminderRule rule) {
diff --git a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
index 5e3d53b8cedb90f8f12645edfcb607bd9a791762..bf1290ccefd13c1e0e022c84ef900d4a9ce21249 100644
--- a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.olat.core.id.Identity;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.reminder.manager.ReminderRuleDAO;
 import org.olat.course.reminder.ui.ScoreRuleEditor;
@@ -65,6 +66,11 @@ public class ScoreRuleSPI implements FilterRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new ScoreRuleEditor(rule, entry);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	public void filter(RepositoryEntry entry, List<Identity> identities, ReminderRule rule) {
diff --git a/src/main/java/org/olat/course/reminder/ui/AttemptsRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/AttemptsRuleEditor.java
index df8f02df1affed6f22f2475e5432179924091a7e..afcbbdc33a4222b3a4053fb50ff4f79fff427db4 100644
--- a/src/main/java/org/olat/course/reminder/ui/AttemptsRuleEditor.java
+++ b/src/main/java/org/olat/course/reminder/ui/AttemptsRuleEditor.java
@@ -95,7 +95,7 @@ public class AttemptsRuleEditor extends RuleEditorFragment {
 		String[] nodeValues = new String[attemptableNodes.size()];
 		
 		for(int i=0; i<attemptableNodes.size(); i++) {
-			CourseNode attemptableNode = attemptableNodes.get(0);
+			CourseNode attemptableNode = attemptableNodes.get(i);
 			nodeKeys[i] = attemptableNode.getIdent();
 			nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )";
 		}
diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java
index 044a9736112fde16757dab38e39eb907c21807ad..628b01741f6fbafc4a5d0212288db91cf5b529ec 100644
--- a/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java
+++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java
@@ -20,6 +20,7 @@
 package org.olat.course.reminder.ui;
 
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Comparator;
 import java.util.List;
 
@@ -37,6 +38,7 @@ import org.olat.core.gui.components.link.Link;
 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.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.modules.reminder.Reminder;
@@ -46,6 +48,7 @@ import org.olat.modules.reminder.ReminderService;
 import org.olat.modules.reminder.RuleEditorFragment;
 import org.olat.modules.reminder.RuleSPI;
 import org.olat.modules.reminder.model.ReminderRules;
+import org.olat.modules.reminder.model.SendTime;
 import org.olat.modules.reminder.rule.DateRuleSPI;
 import org.olat.modules.reminder.ui.ReminderAdminController;
 import org.olat.repository.RepositoryEntry;
@@ -144,7 +147,10 @@ public class CourseReminderEditController extends FormBasicController {
 		contentCont.setRootForm(mainForm);
 		formLayout.add(contentCont);
 		
-		String emailContent = reminder == null ? "" : reminder.getEmailBody();
+		String emailContent = reminder == null ? null : reminder.getEmailBody();
+		if(!StringHelper.containsNonWhitespace(emailContent)) {
+			emailContent = translate("reminder.def.body");
+		}
 		emailEl = uifactory.addRichTextElementForStringDataMinimalistic("email.content", "email.content", emailContent, 10, 60, contentCont, getWindowControl());
 		
 		String buttonPage = velocity_root + "/edit_rules_buttons.html";
@@ -158,7 +164,24 @@ public class CourseReminderEditController extends FormBasicController {
 	protected String getSendTimeDescription() {
 		String interval = reminderModule.getInterval();
 		String desc = translate("interval." + interval);
-		String time = reminderModule.getDefaultSendTime();
+		String time;
+		
+		SendTime parsedTime = SendTime.parse(reminderModule.getDefaultSendTime());
+		if(parsedTime.isValid()) {
+			int hour = parsedTime.getHour();
+			int minute = parsedTime.getMinute();
+			
+			Calendar cal = Calendar.getInstance();
+			cal.set(Calendar.HOUR_OF_DAY, hour);
+			cal.set(Calendar.MINUTE, minute);
+			cal.set(Calendar.SECOND, 0);
+			cal.set(Calendar.MILLISECOND, 0);
+			
+			time = Formatter.getInstance(getLocale()).formatTimeShort(cal.getTime());
+		} else {
+			time = "ERROR";
+		}
+		
 		return translate("send.time.description", new String[] { desc, time} );
 	}
 	
diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
index adb5c0cef05cab3f959538ebf526f3aa359e4967..21a7433eabe647ed7ab5e857793232409da437d6 100644
--- a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
+++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
@@ -114,8 +114,6 @@ public class CourseReminderListController extends FormBasicController implements
 				true, ReminderCols.creationDate.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ReminderCols.lastModified.i18nKey(), ReminderCols.lastModified.ordinal(),
 				true, ReminderCols.lastModified.name()));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ReminderCols.sendTime.i18nKey(), ReminderCols.sendTime.ordinal(),
-				true, ReminderCols.sendTime.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ReminderCols.send.i18nKey(), ReminderCols.send.ordinal(),
 				true, ReminderCols.send.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ReminderCols.tools.i18nKey(), ReminderCols.tools.ordinal()));
diff --git a/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java
index 55a3bf2e2f90c1a89c1e6f3dc989ab01f787fdf4..95d605e53edf2e061afe17532cc63e676ca03f0e 100644
--- a/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java
+++ b/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java
@@ -100,7 +100,7 @@ public class InitialAttemptsRuleEditor extends RuleEditorFragment {
 		String[] nodeValues = new String[attemptableNodes.size()];
 		
 		for(int i=0; i<attemptableNodes.size(); i++) {
-			CourseNode attemptableNode = attemptableNodes.get(0);
+			CourseNode attemptableNode = attemptableNodes.get(i);
 			nodeKeys[i] = attemptableNode.getIdent();
 			nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )";
 		}
diff --git a/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java
index 8d57868a9aabe4166eb93c35d367a0783416282c..9a77780fadf674350f2fb60f0f6ee12fd1c3c9f8 100644
--- a/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java
+++ b/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java
@@ -90,7 +90,7 @@ public class PassedRuleEditor extends RuleEditorFragment {
 		String[] nodeValues = new String[attemptableNodes.size()];
 		
 		for(int i=0; i<attemptableNodes.size(); i++) {
-			CourseNode attemptableNode = attemptableNodes.get(0);
+			CourseNode attemptableNode = attemptableNodes.get(i);
 			nodeKeys[i] = attemptableNode.getIdent();
 			nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )";
 		}
diff --git a/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java
index 1e726b6979613b0e8cecaf34a4413ad8357b1ed9..8448b04317087343e76cad18ecd73071b0761a9b 100644
--- a/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java
+++ b/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java
@@ -94,7 +94,7 @@ public class ScoreRuleEditor extends RuleEditorFragment {
 		String[] nodeValues = new String[attemptableNodes.size()];
 		
 		for(int i=0; i<attemptableNodes.size(); i++) {
-			CourseNode attemptableNode = attemptableNodes.get(0);
+			CourseNode attemptableNode = attemptableNodes.get(i);
 			nodeKeys[i] = attemptableNode.getIdent();
 			nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )";
 		}
diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties
index 43be3091d38820d6da0e12a67983da1811fcc85d..7e8e2944b7d2ea42490366ab837b5cc766cfe51a 100644
--- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties
@@ -7,30 +7,31 @@ course.role.owner=Besitzer
 course.role.ownerAndCoach=Besitzer und Betreuer
 course.role.participant=Teilnehmer
 course.role.participantAndCoach=Betreuer und Teilnehmer
-day=Tagen
+day=Tage
 delete.rule=-
 dialog.modal.delete.text=Wollen Sie wirklich die Erinnerung "{0}" l\u00F6schen?
 duplicate=Duplizieren
 edit.reminder=Erinnerung bearbeiten
 email.content=E-Mail
-error.course.node.found=Kurs Element existiert nicht mehr
+error.course.node.found=Kurselement existiert nicht mehr
 failed=Fehlgeschlagen
 logs=Logs
 month=Monate
 new.reminder=Neue Erinnerung
 passed=Bestanden
 points=Punkte
+reminder.def.body=<p>Liebe(r) $firstname $lastname</p><p>Sie haben sich in den Kurs "$coursename" eingetragen. Jetzt w\u00E4re ein guter Zeitpunkt diesen zu besuchen!</p><p>$courseurl</p><p>Viele Gr\u00FCsse</p>
 reminder.description=Beschreibung
 reminder.id=ID
 reminder.resend=Erinnerung wurde erfolgreich geschickt.
-reminders=Erinerunngen
+reminders=Erinnerungen
 resend=Wieder schicken
-rule.assign.task=Grupenaufgabe Zuweisung
+rule.assign.task=Aufgabe Zuweisung
 rule.attempts=Versuche
 rule.initial.attempts.date=Datum des ersten Versuchs
 rule.passed=Bestanden
 rule.score=Punkte
-rule.submission.task=Grupenaufgabe Dokumente abgeben
+rule.submission.task=Aufgabe Dokumente abgeben
 rules.description=Wenn folgende Bedingungen erf\u00FCllt sind
 send=Erinnerung jetzt schicken
 send.reminder=Geschickte Erinnerungen
diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties
index b7f032d2fe2054898a26d459ae289849b6eeaaf4..2ee68c99aae6632ecf2e8a3991ffe50ce8d0d79b 100644
--- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties
@@ -9,7 +9,7 @@ course.role.participant=Participants
 course.role.participantAndCoach=Coaches and participants
 day=Days
 delete.rule=-
-dialog.modal.delete.text=Do you really want to delete this reminder "{0}"?
+dialog.modal.delete.text=Do you really want to delete the reminder "{0}"?
 duplicate=Duplicate
 edit.reminder=Edit reminder
 email.content=E-Mail
@@ -20,17 +20,18 @@ month=Months
 new.reminder=New reminder
 passed=Passed
 points=Points
+reminder.def.body=<p>Dear $firstname $lastname</p><p>You are registered in the course "$coursename". Now would be a good time to view it!</p><p>$courseurl</p><p>Best regards</p>
 reminder.description=Description
 reminder.id=ID
 reminder.resend=Reminder was successfully sent.
 reminders=Reminders
 resend=Resend
 rule.attempts=Attempts
-rule.assign.task=Group task assignment
+rule.assign.task=Task assignment
 rule.initial.attempts.date=Initial attempt date
 rule.passed=Passed
 rule.score=Score
-rule.submission.task=Group task documents submission
+rule.submission.task=Task documents submission
 rules.description=When matching all of the following conditions
 send=Send reminders now
 send.reminder=Send reminders
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index 31027f4a306c4ab029ce9a389b7651429c4a4ec1..bcd80211d405fe15b701a4036c80ac6b0705d70d 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -981,7 +981,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				OLATResourceable ores = OresHelper.createOLATResourceableInstance("MembersMgmt", 0l);
 				ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 				WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-				MembersManagementMainController ctrl = new MembersManagementMainController(ureq, addToHistory(ureq, bwControl), getRepositoryEntry());
+				MembersManagementMainController ctrl = new MembersManagementMainController(ureq, addToHistory(ureq, bwControl), toolbarPanel, getRepositoryEntry());
 				listenTo(ctrl);
 				membersCtrl = pushController(ureq, translate("command.opensimplegroupmngt"), ctrl);
 				setActiveTool(membersLink);
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 6cc6b248607fbdcb719f84d3b5909497f4453606..8c377ef00082e64cfb597197d287714721cfd8b9 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
@@ -35,7 +35,7 @@ command.options.certificates=Leistungnachweis
 command.options.reminders=Erinnerung
 command.personalnote=Notizen
 command.previous=Zur\u00FCck zur letzten Seite
-command.reminders=Errinerung
+command.reminders=Erinnerung
 command.run=Kurs Laufzeitumgebung
 command.settings=Beschreibung \u00E4ndern
 course.closed = Dieser Kurs wurde beendet und wird nicht l\u00e4nger bearbeitet oder aktualisiert.
diff --git a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml b/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
index aa5ad79eaca56414561de157fdb11bea4aad1342..884901a0a1cfba3b51989f3ecaf5da1561259689 100644
--- a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
+++ b/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
@@ -5,8 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
 	<class name="org.olat.group.BusinessGroupImpl" table="o_gp_business">
-	
-		<cache usage="transactional" />
 		<!--
 		key (see Interface org.olat.core.commons.persistence.Persistable),
 		lastModified (see Interface org.olat.core.commons.persistence.Auditable)
@@ -62,7 +60,6 @@
 	</class>
 
 	<class name="org.olat.group.model.BusinessGroupShortImpl" table="o_gp_business" mutable="false">
-		<cache usage="transactional" />
 		<id name="key" type="long" column="group_id" unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/group/area/BGAreaImpl.hbm.xml b/src/main/java/org/olat/group/area/BGAreaImpl.hbm.xml
index 01c5fb3fc44454d920a283c9e769629cb5fc0e08..f3167027da80128adadf7d540c61b170b9cac70a 100644
--- a/src/main/java/org/olat/group/area/BGAreaImpl.hbm.xml
+++ b/src/main/java/org/olat/group/area/BGAreaImpl.hbm.xml
@@ -5,9 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
     <class name="org.olat.group.area.BGAreaImpl" table="o_gp_bgarea">
-    		
-		<cache usage="transactional" />
-
         <id name="key"
         	type="long"
         	column="area_id"
diff --git a/src/main/java/org/olat/group/area/BGtoAreaRelationImpl.hbm.xml b/src/main/java/org/olat/group/area/BGtoAreaRelationImpl.hbm.xml
index d929c9e915fb3b47a7546788436d0d36b0fee3c5..079584da58a09e58ae91f1470209f071f7a0c6e5 100644
--- a/src/main/java/org/olat/group/area/BGtoAreaRelationImpl.hbm.xml
+++ b/src/main/java/org/olat/group/area/BGtoAreaRelationImpl.hbm.xml
@@ -3,9 +3,6 @@
 
 <hibernate-mapping default-lazy="false">
  <class name="org.olat.group.area.BGtoAreaRelationImpl" table="o_gp_bgtoarea_rel">
- 
-	<cache usage="transactional" />
-
     <id name="key"
 		type="long"
 		column="bgtoarea_id"
diff --git a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml b/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml
index 28936fb5fbf438e317ddf58c19756006d47176aa..74bebc08d5dd323dc562771f720a336de9459434 100644
--- a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml
+++ b/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml
@@ -5,7 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
 	<class name="org.olat.group.model.BusinessGroupViewImpl" table="o_gp_business_v" mutable="false">
-		<cache usage="transactional" />
 
 		<id name="key" type="long" column="group_id" unsaved-value="null">
 			<generator class="hilo"/>
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
index 7b6422b48affbea72e7574499595c3486aae0854..b8561fcb7b9d7ae727a7ffc13cdf6de5e70e44b3 100644
--- a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
@@ -31,6 +31,7 @@ import org.apache.commons.lang.StringEscapeUtils;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.tabbedpane.TabbedPane;
 import org.olat.core.gui.components.tabbedpane.TabbedPaneChangedEvent;
 import org.olat.core.gui.components.velocity.VelocityContainer;
@@ -107,7 +108,7 @@ public class BusinessGroupEditController extends BasicController implements Cont
 	 *          controller does no type specific stuff implicit just by looking at
 	 *          the group type. Type specifig features must be flagged.
 	 */
-	public BusinessGroupEditController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup) {
+	public BusinessGroupEditController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel, BusinessGroup businessGroup) {
 		super(ureq, wControl);
 		
 		// OLAT-4955: setting the stickyActionType here passes it on to any controller defined in the scope of the editor,
@@ -139,7 +140,7 @@ public class BusinessGroupEditController extends BasicController implements Cont
 				collaborationToolsController = new BusinessGroupToolsController(ureq, getWindowControl(), businessGroup);
 				listenTo(collaborationToolsController);
 				
-				membersController = new BusinessGroupMembersController(ureq, getWindowControl(), businessGroup);
+				membersController = new BusinessGroupMembersController(ureq, getWindowControl(), toolbarPanel, businessGroup);
 				listenTo(membersController);
 				
 				//fxdiff VCRP-1,2: access control of resources
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
index 0453b5bac69cb27011ad9f382f0cb6761412b122..fd5924eace2a5cb7ff67dc4f23c8b2d645d771b6 100644
--- a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
@@ -25,6 +25,7 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -68,7 +69,8 @@ public class BusinessGroupMembersController extends BasicController {
 	@Autowired
 	private BusinessGroupService businessGroupService;
 
-	public BusinessGroupMembersController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup) {
+	public BusinessGroupMembersController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
+			BusinessGroup businessGroup) {
 		super(ureq, wControl);
 		
 		this.businessGroup = businessGroup;
@@ -96,7 +98,7 @@ public class BusinessGroupMembersController extends BasicController {
 		mainVC.put("configMembers", configForm.getInitialComponent());
 		
 		SearchMembersParams searchParams = new SearchMembersParams(false, false, false, true, true, true, true);
-		membersController = new MemberListController(ureq, getWindowControl(), businessGroup, searchParams);
+		membersController = new MemberListController(ureq, getWindowControl(), toolbarPanel, businessGroup, searchParams);
 		listenTo(membersController);
 		
 		membersController.reloadModel();
diff --git a/src/main/java/org/olat/group/ui/edit/MemberListController.java b/src/main/java/org/olat/group/ui/edit/MemberListController.java
index 6d7333fa376a107b6369392fab8c98374f3b0a62..596461b55d3351db3d46d09115295072ef917879 100644
--- a/src/main/java/org/olat/group/ui/edit/MemberListController.java
+++ b/src/main/java/org/olat/group/ui/edit/MemberListController.java
@@ -20,9 +20,11 @@
 package org.olat.group.ui.edit;
 
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberView;
 import org.olat.group.ui.main.SearchMembersParams;
 
 /**
@@ -33,11 +35,16 @@ public class MemberListController extends AbstractMemberListController {
 	
 	private final SearchMembersParams searchParams;
 	
-	public MemberListController(UserRequest ureq, WindowControl wControl,
+	public MemberListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			BusinessGroup group, SearchMembersParams searchParams) {
-		super(ureq, wControl, group, "all_member_list");
+		super(ureq, wControl, group, "all_member_list", stackPanel);
 		this.searchParams = searchParams;
 	}
+	
+	@Override
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+		//
+	}
 
 	@Override
 	public SearchMembersParams getSearchParams() {
diff --git a/src/main/java/org/olat/group/ui/edit/_content/all_member_list.html b/src/main/java/org/olat/group/ui/edit/_content/all_member_list.html
index a3ff625a6170395b48de38702a09679fef1e0e83..b4fe28a70ec8110136641d277f8073cf326c7d5b 100644
--- a/src/main/java/org/olat/group/ui/edit/_content/all_member_list.html
+++ b/src/main/java/org/olat/group/ui/edit/_content/all_member_list.html
@@ -1,4 +1,15 @@
 #if($infos)
 	<div class="o_info">$infos</div>
 #end
-$r.render("memberList")
\ No newline at end of file
+$r.render("memberList")
+<div class="o_button_group">
+	#if($r.available("edit.members"))
+		$r.render("edit.members")
+	#end
+	#if($r.available("table.header.mail"))
+		$r.render("table.header.mail")
+	#end
+	#if($r.available("table.header.remove"))
+		$r.render("table.header.remove")
+	#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index 2fcb1cec311002599d59e72ef246a911e561ca76..573788d29080a347ffd8169fa6683e605a75e564 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -19,7 +19,6 @@
  */
 package org.olat.group.ui.main;
 
-import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -29,37 +28,49 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.SearchIdentityParams;
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.table.ColumnDescriptor;
-import org.olat.core.gui.components.table.CustomCellRenderer;
-import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
-import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
-import org.olat.core.gui.components.table.Table;
-import org.olat.core.gui.components.table.TableController;
-import org.olat.core.gui.components.table.TableEvent;
-import org.olat.core.gui.components.table.TableGuiConfiguration;
-import org.olat.core.gui.components.table.TableMultiSelectEvent;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableSearchEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
+import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.StringHelper;
@@ -67,6 +78,7 @@ import org.olat.core.util.Util;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
 import org.olat.core.util.mail.MailPackage;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.session.UserSessionManager;
 import org.olat.course.member.MemberListController;
 import org.olat.group.BusinessGroup;
@@ -92,86 +104,94 @@ import org.olat.repository.model.RepositoryEntryPermissionChangeEvent;
 import org.olat.resource.OLATResource;
 import org.olat.resource.accesscontrol.ACService;
 import org.olat.resource.accesscontrol.model.ResourceReservation;
+import org.olat.user.UserInfoMainController;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public abstract class AbstractMemberListController extends BasicController implements Activateable2 {
+public abstract class AbstractMemberListController extends FormBasicController implements Activateable2 {
 
 	protected static final String USER_PROPS_ID = MemberListController.class.getCanonicalName();
 	
+	public static final int USER_PROPS_OFFSET = 500;
+	
 	public static final String TABLE_ACTION_EDIT = "tbl_edit";
 	public static final String TABLE_ACTION_MAIL = "tbl_mail";
 	public static final String TABLE_ACTION_REMOVE = "tbl_remove";
 	public static final String TABLE_ACTION_GRADUATE = "tbl_graduate";
 	public static final String TABLE_ACTION_IM = "tbl_im";
+	public static final String TABLE_ACTION_HOME = "tbl_home";
+	public static final String TABLE_ACTION_CONTACT = "tbl_contact";
+	public static final String TABLE_ACTION_ASSESSMENT = "tbl_assessment";
+
+	protected FlexiTableElement membersTable;
+	protected MemberListTableModel memberListModel;
+	protected final TooledStackedPanel toolbarPanel;
+	private FormLink editButton, mailButton, removeButton;
 	
-	protected final TableController memberListCtr;
-	protected final VelocityContainer mainVC;
-	
+	private ToolsController toolsCtrl;
 	protected CloseableModalController cmc;
-	private EditMembershipController editMembersCtrl;
-	private EditSingleMembershipController editSingleMemberCtrl;
 	private ContactFormController contactCtrl;
-	private MemberLeaveConfirmationController leaveDialogBox;
 	private DialogBoxController confirmSendMailBox;
+	private UserInfoMainController visitingCardCtrl;
+	private EditMembershipController editMembersCtrl;
+	private MemberLeaveConfirmationController leaveDialogBox;
+	private CloseableCalloutWindowController toolsCalloutCtrl;
+	private EditSingleMembershipController editSingleMemberCtrl;
 	private final List<UserPropertyHandler> userPropertyHandlers;
 
-	private final RepositoryEntry repoEntry;
+	private final AtomicInteger counter = new AtomicInteger();
+	protected final RepositoryEntry repoEntry;
 	private final BusinessGroup businessGroup;
 	private final boolean isLastVisitVisible;
 	private final boolean isAdministrativeUser;
 	private final boolean chatEnabled;
 	private final boolean globallyManaged;
 	
-	private final UserManager userManager;
-	
-	private final BaseSecurity securityManager;
-	private final BaseSecurityModule securityModule;
-	private final RepositoryService repositoryService;
-	private final RepositoryManager repositoryManager;
-	private final BusinessGroupService businessGroupService;
-	private final BusinessGroupModule groupModule;
-	private final ACService acService;
-	private final InstantMessagingModule imModule;
-	private final InstantMessagingService imService;
-	private final UserSessionManager sessionManager;
-	
-	private final GroupMemberViewComparator memberViewComparator;
-	private static final CourseMembershipComparator MEMBERSHIP_COMPARATOR = new CourseMembershipComparator();
-	
+	@Autowired
+	protected UserManager userManager;
+	@Autowired
+	protected BaseSecurity securityManager;
+	@Autowired
+	private BaseSecurityModule securityModule;
+	@Autowired
+	private RepositoryService repositoryService;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
+	private BusinessGroupService businessGroupService;
+	@Autowired
+	private BusinessGroupModule groupModule;
+	@Autowired
+	private ACService acService;
+	@Autowired
+	private InstantMessagingModule imModule;
+	@Autowired
+	private InstantMessagingService imService;
+	@Autowired
+	private UserSessionManager sessionManager;
+
 	public AbstractMemberListController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry,
-			String page) {
-		this(ureq, wControl, repoEntry, null, page, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
+			String page, TooledStackedPanel stackPanel) {
+		this(ureq, wControl, repoEntry, null, page, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
 	}
 	
 	public AbstractMemberListController(UserRequest ureq, WindowControl wControl, BusinessGroup group,
-			String page) {
-		this(ureq, wControl, null, group, page, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
+			String page, TooledStackedPanel stackPanel) {
+		this(ureq, wControl, null, group, page, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
 	}
 	
 	protected AbstractMemberListController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry, BusinessGroup group,
-			String page, Translator translator) {
-		super(ureq, wControl, Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), translator));
+			String page, TooledStackedPanel stackPanel, Translator translator) {
+		super(ureq, wControl, page, Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), translator));
 		
 		this.businessGroup = group;
 		this.repoEntry = repoEntry;
-		
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
-		securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class);
-		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
-		repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
-		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-		groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class);
-		acService = CoreSpringFactory.getImpl(ACService.class);
-		imModule = CoreSpringFactory.getImpl(InstantMessagingModule.class);
-		imService = CoreSpringFactory.getImpl(InstantMessagingService.class);
-		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
-		memberViewComparator = new GroupMemberViewComparator(Collator.getInstance(getLocale()));
+		this.toolbarPanel = stackPanel;
 
 		globallyManaged = calcGloballyManaged();
 		
@@ -179,32 +199,31 @@ public abstract class AbstractMemberListController extends BasicController imple
 		chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled();
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
 		isLastVisitVisible = securityModule.isUserLastVisitVisible(roles);
-		mainVC = createVelocityContainer(page);
-
-		//table
-		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
-		tableConfig.setPreferencesOffered(true, this.getClass().getSimpleName());
-		tableConfig.setTableEmptyMessage(translate("nomembers"));
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, isAdministrativeUser);
 		
-		memberListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), true);
-		listenTo(memberListCtr);
+		initForm(ureq);
+	}
+	
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		initColumns(columnsModel);
+		
+		memberListModel = new MemberListTableModel(columnsModel, imModule.isOnlineStatusEnabled());
+		membersTable = uifactory.addTableElement(getWindowControl(), "memberList", memberListModel, 20, false, getTranslator(), formLayout);
+		membersTable.setMultiSelect(true);
+		membersTable.setEmtpyTableMessageKey("nomembers");
+		membersTable.setAndLoadPersistedPreferences(ureq, this.getClass().getSimpleName());
+		membersTable.setSearchEnabled(true);
 
-		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, isAdministrativeUser);
-		initColumns();
-		MemberListTableModel memberListModel = new MemberListTableModel(userPropertyHandlers);
-		memberListCtr.setTableDataModel(memberListModel);
-		memberListCtr.setMultiSelect(true);
 		if(!globallyManaged) {
-			memberListCtr.addMultiSelectAction("edit.members", TABLE_ACTION_EDIT);
+			editButton = uifactory.addFormLink("edit.members", formLayout, Link.BUTTON);
 		}
-		memberListCtr.addMultiSelectAction("table.header.mail", TABLE_ACTION_MAIL);
+		mailButton = uifactory.addFormLink("table.header.mail", formLayout, Link.BUTTON);
 		if(!globallyManaged) {
-			memberListCtr.addMultiSelectAction("table.header.remove", TABLE_ACTION_REMOVE);
+			removeButton = uifactory.addFormLink("table.header.remove", formLayout, Link.BUTTON);
 		}
-
-		mainVC.put("memberList", memberListCtr.getInitialComponent());
-		
-		putInitialPanel(mainVC);
 	}
 	
 	private boolean calcGloballyManaged() {
@@ -229,59 +248,49 @@ public abstract class AbstractMemberListController extends BasicController imple
 		//
 	}
 	
-	protected void initColumns() {
-		int offset = Cols.values().length;
+	protected void initColumns(FlexiTableColumnModel columnsModel) {
 		if(chatEnabled) {
-			memberListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.online.i18n(), Cols.online.ordinal(), TABLE_ACTION_IM, getLocale(),
-					ColumnDescriptor.ALIGNMENT_LEFT, new OnlineIconRenderer()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.online.i18n(), Cols.online.ordinal()));
 		}
 		if(isAdministrativeUser) {
-			memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.username.i18n(), Cols.username.ordinal(), null, getLocale()));
+			FlexiCellRenderer renderer = new StaticFlexiCellRenderer(TABLE_ACTION_EDIT, new TextFlexiCellRenderer());
+			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.username.i18n(), Cols.username.ordinal(), TABLE_ACTION_EDIT,
+					true, Cols.username.name(), renderer));
 		}
-		int i=0;
+		
+		int colPos = USER_PROPS_OFFSET;
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 			if (userPropertyHandler == null) continue;
+
+			String propName = userPropertyHandler.getName();
 			boolean visible = UserManager.getInstance().isMandatoryUserProperty(USER_PROPS_ID , userPropertyHandler);
-			memberListCtr.addColumnDescriptor(visible, userPropertyHandler.getColumnDescriptor(i++ + offset, null, getLocale()));
+			if(visible) {
+				FlexiColumnModel col;
+				if(UserConstants.FIRSTNAME.equals(propName)
+						|| UserConstants.LASTNAME.equals(propName)) {
+					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+							colPos++, TABLE_ACTION_EDIT, true, propName,
+							new StaticFlexiCellRenderer(TABLE_ACTION_EDIT, new TextFlexiCellRenderer()));
+				} else {
+					col = new DefaultFlexiColumnModel(true, userPropertyHandler.i18nColumnDescriptorLabelKey(), colPos++, true, propName);
+				}
+				columnsModel.addFlexiColumnModel(col);
+			}
 		}
-		
-		memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), null, getLocale()));
+
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), true, Cols.firstTime.name()));
 		if(isLastVisitVisible) {
-			memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), null, getLocale()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), true, Cols.lastTime.name()));
 		}
 		
-		CustomCellRenderer roleRenderer = new CourseRoleCellRenderer(getLocale());
-		memberListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.role.i18n(), Cols.role.ordinal(), null, getLocale(),  ColumnDescriptor.ALIGNMENT_LEFT, roleRenderer) {
-			@Override
-			public int compareTo(final int rowa, final int rowb) {
-				Object a = table.getTableDataModel().getValueAt(rowa,dataColumn);
-				Object b = table.getTableDataModel().getValueAt(rowb,dataColumn);
-				if(a instanceof CourseMembership && b instanceof CourseMembership) {
-					return MEMBERSHIP_COMPARATOR.compare((CourseMembership)a, (CourseMembership)b);
-				}
-				return super.compareTo(rowa, rowb);
-			}
-		});
+		CourseRoleCellRenderer roleRenderer = new CourseRoleCellRenderer(getLocale());
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.role.i18n(), Cols.role.ordinal(), true, Cols.role.name(), roleRenderer));
 		if(repoEntry != null) {
-			CustomCellRenderer groupRenderer = new GroupCellRenderer();
-			memberListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.groups.i18n(), Cols.groups.ordinal(), null, getLocale(),  ColumnDescriptor.ALIGNMENT_LEFT, groupRenderer) {
-				@Override
-				public int compareTo(final int rowa, final int rowb) {
-					Object a = table.getTableDataModel().getValueAt(rowa,dataColumn);
-					Object b = table.getTableDataModel().getValueAt(rowb,dataColumn);
-					if(a instanceof MemberView && b instanceof MemberView) {
-						return memberViewComparator.compare((MemberView)a, (MemberView)b);
-					}
-					return super.compareTo(rowa, rowb);
-				}
-			});
+			GroupCellRenderer groupRenderer = new GroupCellRenderer();
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.groups.i18n(), Cols.groups.ordinal(), true, Cols.groups.name(), groupRenderer));
 		}
 		
-		memberListCtr.addColumnDescriptor(new GraduateColumnDescriptor("table.header.graduate", TABLE_ACTION_GRADUATE, getTranslator()));
-		memberListCtr.addColumnDescriptor(new StaticColumnDescriptor(TABLE_ACTION_EDIT, "table.header.edit", translate("table.header.edit")));
-		if(!globallyManaged) {
-			memberListCtr.addColumnDescriptor(new LeaveColumnDescriptor("table.header.remove", TABLE_ACTION_REMOVE, getTranslator()));
-		}
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.tools.i18n(), Cols.tools.ordinal()));
 	}
 
 	@Override
@@ -290,42 +299,73 @@ public abstract class AbstractMemberListController extends BasicController imple
 	}
 
 	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
+	protected void formOK(UserRequest ureq) {
 		//
 	}
 
 	@Override
-	protected void event(UserRequest ureq, Controller source, Event event) {
-		if (source == memberListCtr) {
-			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
-				TableEvent te = (TableEvent) event;
-				String actionid = te.getActionId();
-
-				MemberView member = (MemberView)memberListCtr.getTableDataModel().getObject(te.getRowId());
-				if(TABLE_ACTION_EDIT.equals(actionid)) {
-					openEdit(ureq, member);
-				} else if(TABLE_ACTION_REMOVE.equals(actionid)) {
-					confirmDelete(ureq, Collections.singletonList(member));
-				} else if(TABLE_ACTION_GRADUATE.equals(actionid)) {
-					doGraduate(Collections.singletonList(member));
-				} else if(TABLE_ACTION_IM.equals(actionid)) {
-					doIm(ureq, member);
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == membersTable) {
+			if(event instanceof SelectionEvent) {
+				SelectionEvent se = (SelectionEvent)event;
+				String cmd = se.getCommand();
+				MemberView row = memberListModel.getObject(se.getIndex());
+				if(TABLE_ACTION_IM.equals(cmd)) {
+					doIm(ureq, row);
+				} else if(TABLE_ACTION_EDIT.equals(cmd)) {
+					openEdit(ureq, row);
 				}
-			} else if (event instanceof TableMultiSelectEvent) {
-				TableMultiSelectEvent te = (TableMultiSelectEvent)event;
-				@SuppressWarnings("unchecked")
-				List<MemberView> selectedItems = memberListCtr.getObjects(te.getSelection());
-				if(TABLE_ACTION_REMOVE.equals(te.getAction())) {
-					confirmDelete(ureq, selectedItems);
-				} else if(TABLE_ACTION_EDIT.equals(te.getAction())) {
-					openEdit(ureq, selectedItems);
-				} else if(TABLE_ACTION_MAIL.equals(te.getAction())) {
-					doSendMail(ureq, selectedItems);
-				} else if(TABLE_ACTION_GRADUATE.equals(te.getAction())) {
-					doGraduate(selectedItems);
+			} else if(event instanceof FlexiTableSearchEvent) {
+				if(FlexiTableSearchEvent.SEARCH.equals(event.getCommand())) {
+					FlexiTableSearchEvent se = (FlexiTableSearchEvent)event;
+					String search = se.getSearch();
+					doSearch(search);
+				} else if(FlexiTableSearchEvent.RESET.equals(event.getCommand())) {
+					doResetSearch();
 				}
 			}
-		} else if (source == leaveDialogBox) {
+		} else if(editButton == source) {
+			List<MemberView> selectedItems = getMultiSelectedRows();
+			openEdit(ureq, selectedItems);
+		} else if(mailButton == source) {
+			List<MemberView> selectedItems = getMultiSelectedRows();
+			doSendMail(ureq, selectedItems);
+		} else if(removeButton == source) {
+			List<MemberView> selectedItems = getMultiSelectedRows();
+			confirmDelete(ureq, selectedItems);
+		} else if(source instanceof FormLink) {
+			FormLink link = (FormLink)source;
+			String cmd = link.getCmd();
+			if("tools".equals(cmd)) {
+				MemberView row = (MemberView)link.getUserObject();
+				doOpenTools(ureq, row, link);
+			} else if("im".equals(cmd)) {
+				MemberView row = (MemberView)link.getUserObject();
+				doIm(ureq, row);
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	private List<MemberView> getMultiSelectedRows() {
+		Set<Integer> selections = membersTable.getMultiSelectedIndex();
+		List<MemberView> rows = new ArrayList<>(selections.size());
+		if(selections.isEmpty()) {
+			//do nothing
+		} else {
+			for(Integer i:selections) {
+				MemberView row = memberListModel.getObject(i.intValue());
+				if(row != null) {
+					rows.add(row);
+				}
+			}
+		}
+		return rows;
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == leaveDialogBox) {
 			if (Event.DONE_EVENT == event) {
 				List<Identity> members = leaveDialogBox.getIdentities();
 				doLeave(members, leaveDialogBox.isSendMail());
@@ -341,6 +381,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 			}
 		} else if(source == editSingleMemberCtrl) {
 			cmc.deactivate();
+			cleanUpPopups();
 			if(event instanceof MemberPermissionChangeEvent) {
 				MemberPermissionChangeEvent e = (MemberPermissionChangeEvent)event;
 				doConfirmChangePermission(ureq, e, null);
@@ -357,6 +398,11 @@ public abstract class AbstractMemberListController extends BasicController imple
 		} else if (source == contactCtrl) {
 			cmc.deactivate();
 			cleanUpPopups();
+		} else if(toolsCtrl == source) {
+			if(event == Event.DONE_EVENT) {
+				toolsCalloutCtrl.deactivate();
+				cleanUpPopups();
+			}
 		} else if (source == cmc) {
 			cleanUpPopups();
 		}
@@ -406,8 +452,10 @@ public abstract class AbstractMemberListController extends BasicController imple
 	}
 	
 	protected void openEdit(UserRequest ureq, MemberView member) {
+		if(editSingleMemberCtrl != null) return;
+		
 		Identity identity = securityManager.loadIdentityByKey(member.getIdentityKey());
-		editSingleMemberCtrl = new EditSingleMembershipController(ureq, getWindowControl(), identity, repoEntry, businessGroup);
+		editSingleMemberCtrl = new EditSingleMembershipController(ureq, getWindowControl(), identity, repoEntry, businessGroup, false);
 		listenTo(editSingleMemberCtrl);
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), editSingleMemberCtrl.getInitialComponent(),
 				true, translate("edit.member"));
@@ -426,6 +474,29 @@ public abstract class AbstractMemberListController extends BasicController imple
 		listenTo(cmc);
 	}
 	
+	protected void doSearch(String search) {
+		getSearchParams().setSearchString(search);
+		reloadModel();
+	}
+	
+	protected void doResetSearch() {
+		getSearchParams().setSearchString(null);
+		reloadModel();
+	}
+	
+	private void doOpenTools(UserRequest ureq, MemberView row, FormLink link) {
+		removeAsListenerAndDispose(toolsCtrl);
+		removeAsListenerAndDispose(toolsCalloutCtrl);
+
+		toolsCtrl = new ToolsController(ureq, getWindowControl(), row);
+		listenTo(toolsCtrl);
+
+		toolsCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),
+				toolsCtrl.getInitialComponent(), link.getFormDispatchId(), "", true, "");
+		listenTo(toolsCalloutCtrl);
+		toolsCalloutCtrl.activate();
+	}
+	
 	/**
 	 * Open private chat
 	 * @param ureq
@@ -561,6 +632,37 @@ public abstract class AbstractMemberListController extends BasicController imple
 		reloadModel();
 	}
 	
+	protected void doOpenVisitingCard(UserRequest ureq, MemberView member) {
+		removeAsListenerAndDispose(visitingCardCtrl);
+		Identity choosenIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+		visitingCardCtrl = new UserInfoMainController(ureq, getWindowControl(), choosenIdentity, false, false);
+		listenTo(visitingCardCtrl);
+		
+		String fullname = userManager.getUserDisplayName(choosenIdentity);
+		toolbarPanel.pushController(fullname, visitingCardCtrl);
+	}
+	
+	protected void doOpenContact(UserRequest ureq, MemberView member) {
+		removeAsListenerAndDispose(contactCtrl);
+		
+		Identity choosenIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+		String fullname = userManager.getUserDisplayName(choosenIdentity);
+		
+		ContactMessage cmsg = new ContactMessage(ureq.getIdentity());
+		ContactList emailList = new ContactList(fullname);
+		emailList.add(choosenIdentity);
+		cmsg.addEmailTo(emailList);
+		
+		OLATResourceable ores = OresHelper.createOLATResourceableType("Contact");
+		WindowControl bwControl = addToHistory(ureq, ores, null);
+		contactCtrl = new ContactFormController(ureq, bwControl, true, false, false, cmsg);
+		listenTo(contactCtrl);
+		
+		toolbarPanel.pushController(fullname, contactCtrl);
+	}
+	
+	protected abstract void doOpenAssessmentTool(UserRequest ureq, MemberView member);
+	
 	protected List<Long> getMemberKeys(List<MemberView> members) {
 		List<Long> keys = new ArrayList<Long>(members.size());
 		if(members != null && !members.isEmpty()) {
@@ -613,16 +715,40 @@ public abstract class AbstractMemberListController extends BasicController imple
 		List<Identity> identities;
 		if(identityKeys.isEmpty()) {
 			identities = new ArrayList<Identity>(0);
-		} else {
+		} else  {
 			SearchIdentityParams idParams = new SearchIdentityParams();
-			idParams.setIdentityKeys(identityKeys);
-			if(params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
-				idParams.setUserProperties(params.getUserPropertiesSearch());
-			}
-			if(StringHelper.containsNonWhitespace(params.getLogin())) {
-				idParams.setLogin(params.getLogin());
+			if(StringHelper.containsNonWhitespace(params.getSearchString())) {
+				String searchString = params.getSearchString();
+				
+				Map<String,String> propertiesSearch = new HashMap<>();
+				for(UserPropertyHandler handler:userPropertyHandlers) {
+					propertiesSearch.put(handler.getName(), searchString);
+				}
+				idParams.setLogin(searchString);
+				idParams.setUserProperties(propertiesSearch);
+			} else {
+				if(params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
+					idParams.setUserProperties(params.getUserPropertiesSearch());
+				}
+				if(StringHelper.containsNonWhitespace(params.getLogin())) {
+					idParams.setLogin(params.getLogin());
+				}
 			}
-			identities = securityManager.getIdentitiesByPowerSearch(idParams, 0, -1);
+			
+			List<Long> identityKeyList = new ArrayList<>(identityKeys);
+			identities = new ArrayList<>(identityKeyList.size());
+
+			int count = 0;
+			int batch = 500;
+			do {
+				int toIndex = Math.min(count + batch, identityKeyList.size());
+				List<Long> toLoad = identityKeyList.subList(count, toIndex);
+				idParams.setIdentityKeys(toLoad);
+
+				List<Identity> batchOfIdentities = securityManager.getIdentitiesByPowerSearch(idParams, 0, -1);
+				identities.addAll(batchOfIdentities);
+				count += batch;
+			} while(count < identityKeyList.size());
 		}
 
 		Map<Long,MemberView> keyToMemberMap = new HashMap<Long,MemberView>();
@@ -644,11 +770,11 @@ public abstract class AbstractMemberListController extends BasicController imple
 				MemberView member = new MemberView(identity, userPropertyHandlers, locale);
 				member.getMembership().setPending(true);
 				memberList.add(member);
+				forgeLinks(member);
 				keyToMemberMap.put(identity.getKey(), member);
 			}
 		}
 		
-		
 		Long me = getIdentity().getKey();
 		Set<Long> loadStatus = new HashSet<Long>();
 		for(Identity identity:identities) {
@@ -663,6 +789,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 				}
 			}
 			memberList.add(member);
+			forgeLinks(member);
 			keyToMemberMap.put(identity.getKey(), member);
 		}
 		
@@ -724,14 +851,29 @@ public abstract class AbstractMemberListController extends BasicController imple
 		//the order of the filter is important
 		filterByRoles(memberList, params);
 		filterByOrigin(memberList, params);
-		((MemberListTableModel)memberListCtr.getTableDataModel()).setObjects(memberList);
-		memberListCtr.modelChanged();
+		
+		memberListModel.setObjects(memberList);
+		membersTable.reset();
 		return memberList;
 	}
 	
+	protected void forgeLinks(MemberView row) {
+		FormLink toolsLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "tools", "", null, null, Link.NONTRANSLATED);
+		toolsLink.setIconLeftCSS("o_icon o_icon_actions o_icon-lg");
+		toolsLink.setTitle(translate("tools"));
+		toolsLink.setUserObject(row);
+		row.setToolsLink(toolsLink);
+		
+		FormLink chatLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "im", "", null, null, Link.NONTRANSLATED);
+		chatLink.setIconLeftCSS("o_icon o_icon_status_unavailable");
+		chatLink.setTitle(" ");
+		chatLink.setUserObject(row);
+		row.setChatLink(chatLink);
+	}
+	
 	private void filterByOrigin(List<MemberView> memberList, SearchMembersParams params) {
 		if(params.isGroupOrigin() && params.isRepoOrigin()) {
-			//do ntohing not very useful :-)
+			//do nothing not very useful :-)
 		} else if(params.isGroupOrigin()) {
 			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
 				CourseMembership m = it.next().getMembership();
@@ -835,4 +977,77 @@ public abstract class AbstractMemberListController extends BasicController imple
 			return e;
 		}
 	}
+	
+	private class ToolsController extends BasicController {
+		
+		private final MemberView row;
+		
+		private final VelocityContainer mainVC;
+		
+		public ToolsController(UserRequest ureq, WindowControl wControl, MemberView row) {
+			super(ureq, wControl);
+			this.row = row;
+			
+			mainVC = createVelocityContainer("tools");
+			List<String> links = new ArrayList<>();
+			
+			//links
+			addLink("home", TABLE_ACTION_HOME, "o_icon o_icon_home", links);
+			addLink("contact", TABLE_ACTION_CONTACT, "o_icon o_icon_mail", links);
+			if(repoEntry != null && "CourseModule".equals(repoEntry.getOlatResource().getResourceableTypeName())) {
+				addLink("assessment", TABLE_ACTION_ASSESSMENT, "o_icon o_icon_certificate", links);
+			}
+			
+			links.add("-");
+			
+			if(row.getMembership().isGroupWaiting()) {
+				addLink("table.header.graduate", TABLE_ACTION_GRADUATE, "o_icon o_icon_graduate", links);
+			}
+
+			addLink("edit.member", TABLE_ACTION_EDIT, "o_icon o_icon_edit", links);
+			
+			if(!globallyManaged) {
+				addLink("table.header.remove", TABLE_ACTION_REMOVE, "o_icon o_icon_remove", links);
+			}
+
+			mainVC.contextPut("links", links);
+			putInitialPanel(mainVC);
+		}
+		
+		private void addLink(String name, String cmd, String iconCSS, List<String> links) {
+			Link link = LinkFactory.createLink(name, cmd, getTranslator(), mainVC, this, Link.LINK);
+			if(iconCSS != null) {
+				link.setIconLeftCSS(iconCSS);
+			}
+			mainVC.put(name, link);
+			links.add(name);
+		}
+
+		@Override
+		protected void doDispose() {
+			//
+		}
+		
+		@Override
+		protected void event(UserRequest ureq, Component source, Event event) {
+			fireEvent(ureq, Event.DONE_EVENT);
+			if(source instanceof Link) {
+				Link link = (Link)source;
+				String cmd = link.getCommand();
+				if(TABLE_ACTION_GRADUATE.equals(cmd)) {
+					doGraduate(Collections.singletonList(row));
+				} else if(TABLE_ACTION_EDIT.equals(cmd)) {
+					openEdit(ureq, row);
+				} else if(TABLE_ACTION_REMOVE.equals(cmd)) {
+					confirmDelete(ureq, Collections.singletonList(row));
+				} else if(TABLE_ACTION_HOME.equals(cmd)) {
+					doOpenVisitingCard(ureq, row);
+				} else if(TABLE_ACTION_CONTACT.equals(cmd)) {
+					doOpenContact(ureq, row);
+				} else if(TABLE_ACTION_ASSESSMENT.equals(cmd)) {
+					doOpenAssessmentTool(ureq, row);
+				}
+			}
+		}
+	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
index b1557bd1762b3ee253862f252d1f8a5f1f14b8ee..d94a565272b869fee9d61d15c1e081b5c281a613 100644
--- a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
@@ -21,9 +21,12 @@ package org.olat.group.ui.main;
 
 import java.util.Locale;
 
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
 import org.olat.core.gui.components.table.CustomCellRenderer;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.Util;
 
@@ -31,48 +34,58 @@ import org.olat.core.util.Util;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class CourseRoleCellRenderer implements CustomCellRenderer {
+public class CourseRoleCellRenderer implements CustomCellRenderer, FlexiCellRenderer {
 	
 	private final Translator translator;
 	
 	public CourseRoleCellRenderer(Locale locale) {
 		translator = Util.createPackageTranslator(CourseRoleCellRenderer.class, locale);
 	}
+	
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
+			FlexiTableComponent source, URLBuilder ubu, Translator translator) {
+		if (cellValue instanceof CourseMembership) {
+			render(target, (CourseMembership) cellValue);
+		}
+	}
 
 	@Override
 	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
 		if (val instanceof CourseMembership) {
-			CourseMembership membership = (CourseMembership)val;
-			
-			boolean and = false;
-			if(membership.isOwner()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.repo.owner"));
-			}
-			if(membership.isRepoTutor()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.repo.tutor"));
-			}
-			if(membership.isGroupTutor()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.group.tutor"));
-			}
-			if(membership.isRepoParticipant()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.repo.participant"));
-			}
-			if(membership.isGroupParticipant()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.group.participant"));
-			}
-			if(membership.isWaiting()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.group.waiting"));
-			}
-			if(membership.isPending()) {
-				and = and(sb, and);
-				sb.append(translator.translate("role.pending"));
-			}
+			render(sb, (CourseMembership) val);
+		}
+	}
+	
+	private void render(StringOutput sb, CourseMembership membership) {
+		boolean and = false;
+		if(membership.isOwner()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.repo.owner"));
+		}
+		if(membership.isRepoTutor()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.repo.tutor"));
+		}
+		if(membership.isGroupTutor()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.group.tutor"));
+		}
+		if(membership.isRepoParticipant()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.repo.participant"));
+		}
+		if(membership.isGroupParticipant()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.group.participant"));
+		}
+		if(membership.isWaiting()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.group.waiting"));
+		}
+		if(membership.isPending()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.pending"));
 		}
 	}
 	
diff --git a/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java b/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java
index fd44590f0b9898acfc9647697f463920cd542d9f..ceaa72e52e7104019009b28303d5b157c193d92f 100644
--- a/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java
+++ b/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java
@@ -44,13 +44,13 @@ public class EditSingleMembershipController extends BasicController {
 	private final RepositoryEntry repoEntry;
 
 	public EditSingleMembershipController(UserRequest ureq, WindowControl wControl,  Identity identity,
-			RepositoryEntry repoEntry, BusinessGroup group) {
+			RepositoryEntry repoEntry, BusinessGroup group, boolean withUserLinks) {
 		super(ureq, wControl);
 		
 		this.repoEntry = repoEntry;
 		
 		VelocityContainer mainVC = createVelocityContainer("edit_single_member");
-		infoCtrl = new MemberInfoController(ureq, wControl, identity, repoEntry);
+		infoCtrl = new MemberInfoController(ureq, wControl, identity, repoEntry, withUserLinks);
 		listenTo(infoCtrl);
 		mainVC.put("infos", infoCtrl.getInitialComponent());
 		
diff --git a/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java b/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
index d347313672e5e018b9a592503c941e1ca1d8df93..ff004d30fd7385dc12d62be150b2a7b6606ff755 100644
--- a/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
@@ -22,9 +22,13 @@ package org.olat.group.ui.main;
 import java.util.List;
 import java.util.Locale;
 
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
 import org.olat.core.gui.components.table.CustomCellRenderer;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroupShort;
 
@@ -32,22 +36,33 @@ import org.olat.group.BusinessGroupShort;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class GroupCellRenderer implements CustomCellRenderer {
+public class GroupCellRenderer implements CustomCellRenderer, FlexiCellRenderer {
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
+			FlexiTableComponent source, URLBuilder ubu, Translator translator) {
+		if (cellValue instanceof MemberView) {
+			render(target, (MemberView) cellValue);
+		}
+	}
 
 	@Override
 	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
 		if (val instanceof MemberView) {
-			MemberView member = (MemberView)val;
-			List<BusinessGroupShort> groups = member.getGroups();
-			if(groups != null && !groups.isEmpty()) {
-				boolean and = false;
-				for(BusinessGroupShort group:groups) {
-					and = and(sb, and);
-					if(group.getName() == null) {
-						sb.append(group.getKey());
-					} else {
-						sb.append(StringHelper.escapeHtml(group.getName()));
-					}
+			render(sb, (MemberView) val);
+		}
+	}
+	
+	private void render(StringOutput sb, MemberView member) {
+		List<BusinessGroupShort> groups = member.getGroups();
+		if(groups != null && !groups.isEmpty()) {
+			boolean and = false;
+			for(BusinessGroupShort group:groups) {
+				and = and(sb, and);
+				if(group.getName() == null) {
+					sb.append(group.getKey());
+				} else {
+					sb.append(StringHelper.escapeHtml(group.getName()));
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/group/ui/main/MemberInfoController.java b/src/main/java/org/olat/group/ui/main/MemberInfoController.java
index ed970b8587ea15ce7d5d0cdc7d8fd640e7bcc3dd..e37cbd8643aecda0c4e7c7c68a7cf36875899116 100644
--- a/src/main/java/org/olat/group/ui/main/MemberInfoController.java
+++ b/src/main/java/org/olat/group/ui/main/MemberInfoController.java
@@ -60,6 +60,8 @@ public class MemberInfoController extends FormBasicController {
 	private Long repoEntryKey;
 	private UserCourseInformations courseInfos;
 	
+	private final boolean withLinks;
+	
 	@Autowired
 	private UserManager userManager;
 	@Autowired
@@ -68,11 +70,12 @@ public class MemberInfoController extends FormBasicController {
 	private UserCourseInformationsManager userCourseInfosMgr;
 	
 	public MemberInfoController(UserRequest ureq, WindowControl wControl, Identity identity,
-			RepositoryEntry repoEntry) {
+			RepositoryEntry repoEntry, boolean withLinks) {
 		super(ureq, wControl, "info_member");
 		setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), getTranslator()));
 
 		this.identity = identity;
+		this.withLinks = withLinks;
 		
 		if(repoEntry != null){
 			repoEntryKey = repoEntry.getKey();
@@ -132,17 +135,19 @@ public class MemberInfoController extends FormBasicController {
 		}
 		
 		//links
-		homeLink = uifactory.addFormLink("home", formLayout, Link.BUTTON);
-		homeLink.setIconLeftCSS("o_icon o_icon_home");
-		formLayout.add("home", homeLink);
-		contactLink = uifactory.addFormLink("contact", formLayout, Link.BUTTON);
-		contactLink.setIconLeftCSS("o_icon o_icon_mail");
-		formLayout.add("contact", contactLink);
-		
-		if(repoEntryKey != null) {
-			assessmentLink = uifactory.addFormLink("assessment", formLayout, Link.BUTTON);
-			assessmentLink.setIconLeftCSS("o_icon o_icon_certificate");
-			formLayout.add("assessment", assessmentLink);
+		if(withLinks) {
+			homeLink = uifactory.addFormLink("home", formLayout, Link.BUTTON);
+			homeLink.setIconLeftCSS("o_icon o_icon_home");
+			formLayout.add("home", homeLink);
+			contactLink = uifactory.addFormLink("contact", formLayout, Link.BUTTON);
+			contactLink.setIconLeftCSS("o_icon o_icon_mail");
+			formLayout.add("contact", contactLink);
+			
+			if(repoEntryKey != null) {
+				assessmentLink = uifactory.addFormLink("assessment", formLayout, Link.BUTTON);
+				assessmentLink.setIconLeftCSS("o_icon o_icon_certificate");
+				formLayout.add("assessment", assessmentLink);
+			}
 		}
 	}
 	
diff --git a/src/main/java/org/olat/group/ui/main/MemberListTableModel.java b/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
index 7bd2def03486e276323645ee210064ff2393f70b..8471a9cc7a84daf591cbc8b0410f78a0afc1d6cf 100644
--- a/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
+++ b/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
@@ -19,50 +19,87 @@
  */
 package org.olat.group.ui.main;
 
-import java.util.Collections;
 import java.util.List;
 
-import org.olat.core.gui.components.table.DefaultTableDataModel;
-import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.instantMessaging.model.Presence;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MemberListTableModel extends DefaultTableDataModel<MemberView> {
+public class MemberListTableModel extends DefaultFlexiTableDataModel<MemberView> implements SortableFlexiTableDataModel<MemberView> {
 	
-	private final List<UserPropertyHandler> userPropertyHandlers;
+	private final boolean onlineStatusEnabled;
 	
-	public MemberListTableModel(List<UserPropertyHandler> userPropertyHandlers) {
-		super(Collections.<MemberView>emptyList());
-		this.userPropertyHandlers = userPropertyHandlers;
+	public MemberListTableModel(FlexiTableColumnModel columnModel, boolean onlineStatusEnabled) {
+		super(columnModel);
+		this.onlineStatusEnabled = onlineStatusEnabled;
 	}
 
 	@Override
-	public int getColumnCount() {
-		return 4 + userPropertyHandlers.size();
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<MemberView> views = new MemberListTableSort(orderBy, this, null).sort();
+			super.setObjects(views);
+		}
 	}
 
 	@Override
 	public Object getValueAt(int row, int col) {
 		MemberView member = getObject(row);
-		switch(col) {
-			case 0:return member.getIdentityName();
-			case 1: return member.getFirstTime();
-			case 2: return member.getLastTime();
-			case 3: return member.getMembership();
-			case 4: return member;
-			case 5:return member.getOnlineStatus();
-			default: {
-				int propPos = col - Cols.values().length;
-				return member.getIdentityProp(propPos);
+		return getValueAt(member, col);
+	}
+
+	@Override
+	public Object getValueAt(MemberView row, int col) {
+		if(col >= 0 && col < Cols.values().length) {
+			switch(Cols.values()[col]) {
+				case username: return row.getIdentityName();
+				case firstTime: return row.getFirstTime();
+				case lastTime: return row.getLastTime();
+				case role: return row.getMembership();
+				case groups: return row;
+				case online: {
+					FormLink chatLink = row.getChatLink();
+					if(chatLink != null) {
+						String onlineStatus = row.getOnlineStatus();
+						if ("me".equals(onlineStatus)) {
+							//no icon
+						} else if (!onlineStatusEnabled) {
+							// don't show the users status when not configured, only an icon to start a chat/message
+							chatLink.setIconLeftCSS("o_icon o_icon_status_chat");
+						}
+						// standard case: available or unavailable (offline or dnd)
+						else if(Presence.available.name().equals(onlineStatus)) {
+							chatLink.setIconLeftCSS("o_icon o_icon_status_available");
+						} else if(Presence.dnd.name().equals(onlineStatus)) {
+							chatLink.setIconLeftCSS("o_icon o_icon_status_dnd");
+						} else {
+							chatLink.setIconLeftCSS("o_icon o_icon_status_unavailable");
+						}
+						if(chatLink.getComponent() != null) {
+							chatLink.getComponent().setDirty(false);
+						}
+					}
+					return chatLink;
+				}
+				case tools: return row.getToolsLink();
+				default: return "ERROR";
 			}
 		}
+		
+		int propPos = col - AbstractMemberListController.USER_PROPS_OFFSET;
+		return row.getIdentityProp(propPos);
 	}
 
 	@Override
-	public Object createCopyWithEmptyList() {
-		return new MemberListTableModel(userPropertyHandlers);
+	public MemberListTableModel createCopyWithEmptyList() {
+		return new MemberListTableModel(getTableColumnModel(), onlineStatusEnabled);
 	}
 
 	public enum Cols {
@@ -71,7 +108,8 @@ public class MemberListTableModel extends DefaultTableDataModel<MemberView> {
 		lastTime("table.header.lastTime"),
 		role("table.header.role"),
 		groups("table.header.groups"),
-		online("table.header.online");
+		online("table.header.online"),
+		tools("tools");
 		
 		private final String i18n;
 		
diff --git a/src/main/java/org/olat/group/ui/main/MemberListTableSort.java b/src/main/java/org/olat/group/ui/main/MemberListTableSort.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ef5dc89e5a5792e99fc79b02ab6285649f53bce
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/MemberListTableSort.java
@@ -0,0 +1,53 @@
+package org.olat.group.ui.main;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.group.ui.main.MemberListTableModel.Cols;
+
+/**
+ * 
+ * Initial date: 18.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MemberListTableSort extends SortableFlexiTableModelDelegate<MemberView> {
+	
+	
+	
+	public MemberListTableSort(SortKey orderBy, SortableFlexiTableDataModel<MemberView> tableModel, Locale locale) {
+		super(orderBy, tableModel, locale);
+	}
+
+	@Override
+	protected void sort(List<MemberView> rows) {
+		int columnIndex = getColumnIndex();
+		Cols column = Cols.values()[columnIndex];
+		switch(column) {
+			case role:
+				Collections.sort(rows, new RoleMemberViewComparator());
+				break;
+			case groups:
+				Collections.sort(rows, new GroupMemberViewComparator(getCollator()));
+				break;
+			default: {
+				super.sort(rows);
+			}
+		}
+	}
+
+	private static class RoleMemberViewComparator implements Comparator<MemberView> {
+		
+		private final CourseMembershipComparator comparator = new CourseMembershipComparator();
+
+		@Override
+		public int compare(MemberView o1, MemberView o2) {
+			return comparator.compare(o1.getMembership(), o2.getMembership());
+		}
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/MemberView.java b/src/main/java/org/olat/group/ui/main/MemberView.java
index 4f1da69392c057185ae7d85444d8c8dd90efc669..e7fdf035b58d46af6f064dc9ad12dd919f51228b 100644
--- a/src/main/java/org/olat/group/ui/main/MemberView.java
+++ b/src/main/java/org/olat/group/ui/main/MemberView.java
@@ -24,46 +24,44 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupShort;
+import org.olat.user.UserPropertiesRow;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MemberView {
+public class MemberView extends UserPropertiesRow {
 	
-	private final Long identityKey;
-	private final String identityName;
-	private final String[] identityProps;
 	private Date firstTime;
 	private Date lastTime;
 	private final CourseMembership membership = new CourseMembership();
 	private List<BusinessGroupShort> groups;
 	private String onlineStatus;
+	private FormLink toolsLink, chatLink;
 	
 	public MemberView(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
-		this.identityKey = identity.getKey();
-		this.identityName = identity.getName();
-		
-		identityProps = new String[userPropertyHandlers.size()];
-		for(int i=userPropertyHandlers.size(); i-->0; ) {
-			identityProps[i] = userPropertyHandlers.get(i).getUserProperty(identity.getUser(), locale);
-		}
+		super(identity, userPropertyHandlers, locale);
 	}
 
-	public Long getIdentityKey() {
-		return identityKey;
+	public FormLink getToolsLink() {
+		return toolsLink;
 	}
 
-	public String getIdentityName() {
-		return identityName;
+	public void setToolsLink(FormLink toolsLink) {
+		this.toolsLink = toolsLink;
 	}
-	
-	public String getIdentityProp(int index) {
-		return identityProps[index];
+
+	public FormLink getChatLink() {
+		return chatLink;
+	}
+
+	public void setChatLink(FormLink chatLink) {
+		this.chatLink = chatLink;
 	}
 
 	public String getOnlineStatus() {
diff --git a/src/main/java/org/olat/group/ui/main/SearchMembersParams.java b/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
index b02d84acad41a4c5bc9b47e55a3bb9f19e703905..e6cbeb9fe05642dc286c1bcfd55f77ec94f311a0 100644
--- a/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
+++ b/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
@@ -42,6 +42,7 @@ public class SearchMembersParams extends Event {
 	private boolean groupOrigin = true;
 	
 	private String login;
+	private String searchString;
 	private Map<String, String> userPropertiesSearch;
 	
 	public SearchMembersParams() {
@@ -141,6 +142,14 @@ public class SearchMembersParams extends Event {
 		this.login = login;
 	}
 
+	public String getSearchString() {
+		return searchString;
+	}
+
+	public void setSearchString(String searchString) {
+		this.searchString = searchString;
+	}
+
 	public Map<String, String> getUserPropertiesSearch() {
 		return userPropertiesSearch;
 	}
diff --git a/src/main/java/org/olat/group/ui/main/_content/edit_member.html b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
index 2bde8eae942b8baa644f2376d01cdf9866ab7075..e1ae7b03c7fd7f635e1e272059520b61b0355d0e 100644
--- a/src/main/java/org/olat/group/ui/main/_content/edit_member.html
+++ b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
@@ -11,5 +11,5 @@
 	</fieldset>
 #end
 #if($r.available("buttonLayout"))
-	$r.render("buttonLayout")
+	<div class="o_button_group">$r.render("buttonLayout")</div>
 #end
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_content/info_member.html b/src/main/java/org/olat/group/ui/main/_content/info_member.html
index 65976bd477761bb0a8e647be78f2e5d90a1f92ea..83eb98753fa8ad1c599dcf1bd5ed6cfecedf2515 100644
--- a/src/main/java/org/olat/group/ui/main/_content/info_member.html
+++ b/src/main/java/org/olat/group/ui/main/_content/info_member.html
@@ -1,12 +1,18 @@
 <div class="o_header_with_buttons">
 	<h3>$fullname</h3>
+	#if($r.available("home") || $r.available("contact") || $r.available("assessment"))
 	<div class="o_button_group o_button_group_right">
-		$r.render("home")
-		$r.render("contact")
+		#if($r.available("home"))
+			$r.render("home")
+		#end
+		#if($r.available("contact"))
+			$r.render("contact")
+		#end
 		#if($r.available("assessment"))
 			$r.render("assessment")
 		#end
 	</div>
+	#end
 </div>
 <div class="o_user_infos">
 	<div class="o_user_portrait">$r.render("image")</div>
diff --git a/src/main/java/org/olat/group/ui/main/_content/tools.html b/src/main/java/org/olat/group/ui/main/_content/tools.html
new file mode 100644
index 0000000000000000000000000000000000000000..ee364a66e1151caa279c872f06410e111e07e20d
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/_content/tools.html
@@ -0,0 +1,9 @@
+<ul class="o_dropdown list-unstyled">
+#foreach($link in $links)
+	#if($link == "-")
+	<li class="divider"></li>
+	#else	
+	<li>$r.render($link)</li>
+	#end
+#end
+</ul>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index c62240ca6338edcfbe02e4b9bbb8085fe4aa8d2f..7c2a25eef403a11c6bee60361e449e669636beea 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -72,6 +72,7 @@ search.resources=In Kursen verwendet
 search.headless=Orphans
 search.headless.check=Gruppen ohne Mitglieder und Ressourcen
 search.id.format=Keine g\u00FCltige Gruppen-ID
+tools=<i class="o_icon o_icon_actions o_icon-lg"> </i>
 cif.displayname=Name
 cif.description=Beschreibung
 cif.owner=Betreuer
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
index add1eb7445f7d64e9378d41ed06f897ef6e865be..832370e7cca85cf826550c7d5d5324494a2595f6 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
@@ -167,6 +167,7 @@ table.leave=Leave
 table.merge=Merge
 table.users.management=Manage members
 tbl_graduate=$\:table.header.graduate
+tools=<i class="o_icon o_icon_actions o_icon-lg"> </i>
 tools.add.buddygroup=Group
 tools.add.header=Create
 tools.delete.header=Delete
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
index 0743a445bb39b0db07a7cb991f9c2a9c47dbab85..682cefa6288a0d2032fb6f31a959ceaa1d468a18 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
@@ -44,6 +44,7 @@ import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.table.Table;
 import org.olat.core.gui.components.table.TableController;
 import org.olat.core.gui.components.table.TableEvent;
@@ -65,6 +66,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.HistoryPoint;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.activity.OlatResourceableType;
@@ -177,6 +179,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 
 	private Panel mainPanel;
 	private VelocityContainer main, vc_sendToChooserForm, resourcesVC;
+	private final TooledStackedPanel toolbarPanel;
 	private Translator resourceTrans;
 
 	private BusinessGroup businessGroup;
@@ -216,6 +219,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 	private BusinessGroupService businessGroupService;
 	private EventBus singleUserEventBus;
 	private String adminNodeId; // reference to admin menu item
+	private HistoryPoint launchedFromPoint;
 
 	// not null indicates tool is enabled
 	private GenericTreeNode nodeFolder, nodeForum, nodeWiki, nodeCal, nodePortfolio, nodeOpenMeetings;
@@ -241,6 +245,27 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		super(ureq, control);
 		
 		assessmentEventOres = OresHelper.createOLATResourceableType(AssessmentEvent.class);
+		
+		toolbarPanel = new TooledStackedPanel("courseStackPanel", getTranslator(), this);
+		toolbarPanel.setInvisibleCrumb(0); // show root (course) level
+		toolbarPanel.setToolbarEnabled(false);
+		toolbarPanel.setShowCloseLink(true, true);
+
+		UserSession session = ureq.getUserSession();
+		if(session != null &&  session.getHistoryStack() != null && session.getHistoryStack().size() >= 2) {
+			// Set previous business path as back link for this course - brings user back to place from which he launched the course
+			List<HistoryPoint> stack = session.getHistoryStack();
+			for(int i=stack.size() - 2; i-->0; ) {
+				HistoryPoint point = stack.get(stack.size() - 2);
+				if(point.getEntries().size() > 0) {
+					OLATResourceable ores = point.getEntries().get(0).getOLATResourceable();
+					if(!OresHelper.equals(bGroup, ores) && !OresHelper.equals(bGroup.getResource(), ores)) {
+						launchedFromPoint = point;
+						break;
+					}
+				}
+			}
+		}
 
 		/*
 		 * lastUsage, update lastUsage if group is run if you can acquire the lock
@@ -298,17 +323,17 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 
 		mainPanel = new Panel("p_buddygroupRun");
 		mainPanel.setContent(main);
-		//
+		
 		bgTree = new MenuTree("bgTree");
 		TreeModel trMdl = buildTreeModel();
 		bgTree.setTreeModel(trMdl);
 		bgTree.addListener(this);
-		//
+		
 		columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), bgTree, mainPanel, "grouprun");
+		toolbarPanel.pushController(bGroup.getName(), columnLayoutCtr);
 		listenTo(columnLayoutCtr); // cleanup on dispose
+		putInitialPanel(toolbarPanel);
 		
-		//
-		putInitialPanel(columnLayoutCtr.getInitialComponent());
 		// register for AssessmentEvents triggered by this user
 		singleUserEventBus = ureq.getUserSession().getSingleUserEventCenter();
 		singleUserEventBus.registerFor(this, ureq.getIdentity(), assessmentEventOres);
@@ -413,6 +438,10 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 				handleTreeActions(ureq, ACTIVITY_MENUSELECT_OVERVIEW);
 				this.showError("grouprun.disabled");
 			}
+		} else if(source == toolbarPanel) {
+			if (event == Event.CLOSE_EVENT) {
+				doClose(ureq);
+			}
 		}
 	}
 
@@ -732,7 +761,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		//fxdiff BAKS-7 Resume function
 		ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ORES_TOOLADMIN));
 		WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ORES_TOOLADMIN, null, getWindowControl());
-		collabToolCtr = bgEditCntrllr = new BusinessGroupEditController(ureq, bwControl, businessGroup);
+		collabToolCtr = bgEditCntrllr = new BusinessGroupEditController(ureq, bwControl, toolbarPanel, businessGroup);
 		listenTo(bgEditCntrllr);
 		mainPanel.setContent(bgEditCntrllr.getInitialComponent());
 	}
@@ -798,6 +827,12 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		collabToolCtr = null;
 		addToHistory(ureq, ORES_TOOLMEMBERS, null);
 	}
+	
+	protected final void doClose(UserRequest ureq) {
+		OLATResourceable ores = businessGroup.getResource();
+		getWindowControl().getWindowBackOffice().getWindow()
+			.getDTabs().closeDTab(ureq, ores, launchedFromPoint);
+	}
 
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
diff --git a/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java b/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java
index d548df2ad7937f060a61d0c01ea1d0f357187d1a..bedd6b026110e8daf41b9f4f6c0688b71fa26c67 100644
--- a/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java
+++ b/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java
@@ -32,8 +32,10 @@ import org.olat.core.util.filter.FilterFactory;
 import org.olat.ims.qti.editor.QTIEditHelper;
 import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion;
 import org.olat.ims.qti.editor.beecom.objects.ChoiceResponse;
+import org.olat.ims.qti.editor.beecom.objects.Control;
 import org.olat.ims.qti.editor.beecom.objects.FIBQuestion;
 import org.olat.ims.qti.editor.beecom.objects.FIBResponse;
+import org.olat.ims.qti.editor.beecom.objects.Item;
 import org.olat.ims.qti.editor.beecom.objects.Material;
 import org.olat.ims.qti.editor.beecom.objects.Mattext;
 import org.olat.ims.qti.editor.beecom.objects.QTIObject;
@@ -103,6 +105,8 @@ public class CSVToQuestionConverter {
 			case "points": processPoints(parts); break;
 			case "fachbereich":
 			case "subject": processTaxonomyPath(parts); break;
+			case "feedback correct answer": processFeedbackCorrectAnswer(parts); break;
+			case "feedback wrong answer": processFeedbackWrongAnswer(parts); break;
 			case "schlagworte":
 			case "keywords": processKeywords(parts); break;
 			case "abdeckung":
@@ -173,6 +177,34 @@ public class CSVToQuestionConverter {
 		}
 	}
 	
+	private void processFeedbackCorrectAnswer(String[] parts) {
+		if(currentItem == null || parts.length < 2) return;
+		
+		String feedback = parts[1];
+		if(StringHelper.containsNonWhitespace(feedback)) {
+			Item item = currentItem.getItem();
+			Control control = QTIEditHelper.getControl(item);
+			if(control.getFeedback() != 1) {
+				control.setFeedback(1);
+			}
+			QTIEditHelper.setFeedbackMastery(item, feedback);
+		}
+	}
+	
+	private void processFeedbackWrongAnswer(String[] parts) {
+		if(currentItem == null || parts.length < 2) return;
+		
+		String feedback = parts[1];
+		if(StringHelper.containsNonWhitespace(feedback)) {
+			Item item = currentItem.getItem();
+			Control control = QTIEditHelper.getControl(item);
+			if(control.getFeedback() != 1) {
+				control.setFeedback(1);
+			}
+			QTIEditHelper.setFeedbackFail(item, feedback);
+		}
+	}
+	
 	private void processDistractors(String[] parts) {
 		if(currentItem == null || parts.length < 2) return;
 		
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
index d03b6785982c4f900c7c9a999eb7c6ab337c55c1..bc687eb2cc5dee539ea55569b3d84e513bade90c 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
@@ -107,7 +107,7 @@ public abstract class QTIHandler extends FileHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		//getFileResource search the first zip
diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentHandler.java b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentHandler.java
index 2dd09955fde72c203749a739dd1a5357e5d8f400..671067528720fc7ba7287adbf263099f994a2d27 100644
--- a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentHandler.java
+++ b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentHandler.java
@@ -110,9 +110,9 @@ public class QTI21AssessmentHandler extends FileHandler {
 	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
 		return null;
 	}
-
+	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		return null;
 	}
 
diff --git a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementDetailsController.java b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementDetailsController.java
index ec75f7985a6fe3ebef926f025686738494a2a25c..0de9ad93cc80d18cc340a958ad112ef3616c865a 100644
--- a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementDetailsController.java
+++ b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementDetailsController.java
@@ -94,7 +94,8 @@ public class EfficiencyStatementDetailsController extends BasicController implem
 		if(entry != null) {
 			try {
 				ICourse course = CourseFactory.loadCourse(entry.getOlatResource());
-				assessmentCtrl = new IdentityAssessmentEditController(wControl, ureq, null, assessedIdentity, course, true, false);
+				assessmentCtrl = new IdentityAssessmentEditController(wControl, ureq, null,
+						assessedIdentity, course, true, false, false);
 				listenTo(assessmentCtrl);
 				
 				segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
diff --git a/src/main/java/org/olat/modules/fo/FilterForUserController.java b/src/main/java/org/olat/modules/fo/FilterForUserController.java
index 86a8267b1701ae35579bad7bdf1ca3717194efb3..ba33f14ca126928a9533072d8e86669e5fea387b 100644
--- a/src/main/java/org/olat/modules/fo/FilterForUserController.java
+++ b/src/main/java/org/olat/modules/fo/FilterForUserController.java
@@ -347,8 +347,9 @@ public class FilterForUserController extends BasicController {
 					showMessages(ureq, selectedInfo);
 				} else if (te.getActionId().equals(CMD_HOMEPAGE)) {
 					ControllerCreator ctrlCreator = new ControllerCreator() {
+						@Override
 						public Controller createController(UserRequest lureq, WindowControl lwControl) {
-							return new UserInfoMainController(lureq, lwControl, selectedInfo.getIdentity());
+							return new UserInfoMainController(lureq, lwControl, selectedInfo.getIdentity(), true, false);
 						}
 					};
 					// wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
index d7915034ab6820e0696c1e43d1cd8dcc9f694008..71d1d0097fd23387815d4d64677d81ac2f094c6c 100644
--- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
@@ -44,7 +44,7 @@ create.test=Test erstellen
 delete.collection=Liste l\u00F6schen
 delete.item=L\u00F6schen
 delete.pool=Pool l\u00F6schen
-delete.pool.confirm=Wollen Sie wirklich diesen Pool "{0}" l\u00F6schen?
+delete.pool.confirm=Wollen Sie wirklich den Pool "{0}" l\u00F6schen?
 details=Detailansicht
 edit.pool=Pool editieren
 editable=Editierbar
@@ -84,15 +84,15 @@ import.failed=Frage konnte nicht importiert werden.
 import.file=ZIP-Datei von lokalem Computer
 import.item=Import
 import.repository=Test/Fragebogen aus Autorenbereich
-import.success={0} Frage wurde erfolgreich importiert.
+import.success={0} Frage(n) erfolgreich importiert
 import.excellike=Excelimport über Copy&Paste
 inReview=In Review
 inWork=In Bearbeitung
-item.collectioned=Frage {0} wurde in der Liste hinzugef\u00FCgt.
+item.collectioned=Frage {0} wurde zur Liste hinzugef\u00FCgt.
 item.copied={0} Frage wurde kopiert.
 item.deleted=Frage wurde gel\u00F6scht.
 item.level=Level
-item.pooled=Frage {0} wurde im Pool hinzugef\u00FCgt.
+item.pooled=Frage {0} wurde zum Pool hinzugef\u00FCgt.
 item.shared=Frage {0} wurde freigegeben.
 item.type.essay=Essay
 item.type.fib=Fill-in-Blank
diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
index 465df979a70520eb255a4e8d0f271310b8883c49..fea5e5b8720da3d992f55864e8435de6794fa442 100644
--- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
@@ -81,15 +81,15 @@ help.hover.removeitem=Help regarding the removal of items
 help.hover.sharegroup=Help regarding sharing with groups
 help.hover.sharepool=Help regarding sharing with pools
 import.excellike=Excel import via copy&paste
-import.failed=Questions has not been imported.
+import.failed=No questions were imported
 import.file=ZIP-file from local computer
 import.item=Import
 import.repository=Tests/questionnaires from authoring environment
-import.success={0} questions has been imported.
+import.success={0} question(s) successfully imported
 inReview=In review
 inWork=In work
 item.collectioned=Question {0} has been added to the list.
-item.copied={0} question(s) has been copied.
+item.copied={0} question(s) copied
 item.deleted=Question has been deleted.
 item.level=Level
 item.pooled=Question {0} has been added to the pool.
@@ -182,7 +182,7 @@ select.pool=Share with pool
 share.editable=Edit
 share.group=Share with group
 share.item=Share
-share.options=Do you want to allow another person to edit this/these question(s)? 
+share.options=Do you want to allow other users to edit the imported question(s)? 
 share.pool=Share with pool
 share.presentation.1=In Shares you find all the questions shared by other users.
 share.presentation.10=with groups. Only members of that group who also have access rights to the question bank will see this question share.
diff --git a/src/main/java/org/olat/modules/reminder/ReminderModule.java b/src/main/java/org/olat/modules/reminder/ReminderModule.java
index 8897b11119733e9c3aae1bd7544d94bb38f01355..41d5017bbf883a1983a775ac93451501a37bd2bd 100644
--- a/src/main/java/org/olat/modules/reminder/ReminderModule.java
+++ b/src/main/java/org/olat/modules/reminder/ReminderModule.java
@@ -236,7 +236,8 @@ public class ReminderModule extends AbstractSpringModule {
 	public void setScheduler(String interval, String defaultSendTime) {
 		this.interval = interval;
 		this.defaultSendTime = defaultSendTime;
-		setStringProperty(INTERVAL, interval, true);
-		setStringProperty(SEND_TIME, defaultSendTime, true);
+		setStringProperty(INTERVAL, interval, false);
+		setStringProperty(SEND_TIME, defaultSendTime, false);
+		savePropertiesAndFireChangedEvent();
 	}
 }
diff --git a/src/main/java/org/olat/modules/reminder/ReminderRule.java b/src/main/java/org/olat/modules/reminder/ReminderRule.java
index 63c5596224ce2f3731124b43f4b1624c0ba8a510..9f9c2204822ee366366e9fa1c5a5b99fd89c6cae 100644
--- a/src/main/java/org/olat/modules/reminder/ReminderRule.java
+++ b/src/main/java/org/olat/modules/reminder/ReminderRule.java
@@ -19,14 +19,17 @@
  */
 package org.olat.modules.reminder;
 
+
 /**
  * 
  * Initial date: 07.04.2015<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public interface ReminderRule {
+public interface ReminderRule extends Cloneable {
 	
 	public String getType();
+	
+	public ReminderRule clone();
 
 }
diff --git a/src/main/java/org/olat/modules/reminder/ReminderService.java b/src/main/java/org/olat/modules/reminder/ReminderService.java
index d268025f77611dfc478e28c67664074b6ffb3ddb..e6c2cb964b5f9ba55a282b6c278be152d74999a2 100644
--- a/src/main/java/org/olat/modules/reminder/ReminderService.java
+++ b/src/main/java/org/olat/modules/reminder/ReminderService.java
@@ -19,6 +19,7 @@
  */
 package org.olat.modules.reminder;
 
+import java.io.File;
 import java.util.List;
 
 import org.olat.core.id.Identity;
@@ -35,6 +36,8 @@ import org.olat.repository.RepositoryEntryRef;
  *
  */
 public interface ReminderService {
+
+	public static final String REMINDERS_XML = "Reminders.xml";
 	
 	/**
 	 * Create a non-persisted reminder.
@@ -47,6 +50,8 @@ public interface ReminderService {
 	
 	public Reminder loadByKey(Long key);
 	
+	public List<Reminder> getReminders(RepositoryEntryRef entry);
+	
 	public List<ReminderInfos> getReminderInfos(RepositoryEntryRef entry);
 	
 	public Reminder duplicate(Reminder toCopy);
@@ -80,5 +85,15 @@ public interface ReminderService {
 	public String toXML(ReminderRules rules);
 	
 	public ReminderRules toRules(String rulesXml);
+	
+	public void exportReminders(RepositoryEntry entry, File fExportedDataDir);
+	
+	/**
+	 * The reminders are not persisted and not converted to any new course, group...
+	 * 
+	 * @param fExportedDataDir
+	 * @return
+	 */
+	public List<Reminder> importRawReminders(Identity creator, RepositoryEntry newEntry, File fExportedDataDir);
 
 }
diff --git a/src/main/java/org/olat/modules/reminder/RuleSPI.java b/src/main/java/org/olat/modules/reminder/RuleSPI.java
index 97d522d70b2dc7e88bcc49b5ae52eb72475af479..8f876da9955491f0b9290678b2aefec67041107f 100644
--- a/src/main/java/org/olat/modules/reminder/RuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/RuleSPI.java
@@ -19,6 +19,7 @@
  */
 package org.olat.modules.reminder;
 
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.repository.RepositoryEntry;
 
 /**
@@ -33,6 +34,8 @@ public interface RuleSPI {
 	
 	public String getCategory();
 	
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper);
+	
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry);
 
 }
diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java
index f3b21794301e12d529474f65490b594476746310..e21c432694dee92cc00986ef74363256027ed137 100644
--- a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java
+++ b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java
@@ -105,10 +105,17 @@ public class ReminderDAO {
 		return reminder;
 	}
 
-	public void delete(Reminder reminder) {
+	public int delete(Reminder reminder) {
 		ReminderImpl ref = dbInstance.getCurrentEntityManager()
 				.getReference(ReminderImpl.class, reminder.getKey());
+		String del = "delete from sentreminder sent where sent.reminder.key=:reminderKey";
+		int numOfDeletedRows = dbInstance.getCurrentEntityManager()
+				.createQuery(del)
+				.setParameter("reminderKey", reminder.getKey())
+				.executeUpdate();
 		dbInstance.getCurrentEntityManager().remove(ref);
+		numOfDeletedRows++;
+		return numOfDeletedRows;
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java b/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java
index 40d9bb31b89866a6c0c71483242dcbfc1785362c..b4edfa7e3258bfd30f449b8d7e3ac146ad6659d4 100644
--- a/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java
+++ b/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java
@@ -19,11 +19,22 @@
  */
 package org.olat.modules.reminder.manager;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.text.ParseException;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.UUID;
 
+import org.apache.velocity.VelocityContext;
+import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
+import org.olat.core.id.User;
+import org.olat.core.id.UserConstants;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Formatter;
@@ -33,12 +44,15 @@ import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.modules.reminder.Reminder;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.ReminderService;
 import org.olat.modules.reminder.SentReminder;
+import org.olat.modules.reminder.model.ImportExportReminder;
+import org.olat.modules.reminder.model.ImportExportReminders;
 import org.olat.modules.reminder.model.ReminderImpl;
 import org.olat.modules.reminder.model.ReminderInfos;
 import org.olat.modules.reminder.model.ReminderRuleImpl;
@@ -46,6 +60,7 @@ import org.olat.modules.reminder.model.ReminderRules;
 import org.olat.modules.reminder.rule.DateRuleSPI;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
+import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -65,14 +80,19 @@ public class ReminderServiceImpl implements ReminderService {
 	static {
 		ruleXStream.alias("rule", org.olat.modules.reminder.model.ReminderRuleImpl.class);
 		ruleXStream.alias("rules", org.olat.modules.reminder.model.ReminderRules.class);
+		ruleXStream.alias("reminders", org.olat.modules.reminder.model.ImportExportReminders.class);
+		ruleXStream.alias("reminder", org.olat.modules.reminder.model.ImportExportReminder.class);
 	}
 	
+	
 	@Autowired
 	private ReminderDAO reminderDao;
 	@Autowired
-	private ReminderRuleEngine ruleEngine;
-	@Autowired
 	private MailManager mailManager;
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private ReminderRuleEngine ruleEngine;
 	
 	@Override
 	public Reminder createReminder(RepositoryEntry entry, Identity creator) {
@@ -117,6 +137,11 @@ public class ReminderServiceImpl implements ReminderService {
 		return reminderDao.loadByKey(key);
 	}
 	
+	@Override
+	public List<Reminder> getReminders(RepositoryEntryRef entry) {
+		return reminderDao.getReminders(entry);
+	}
+
 	@Override
 	public List<ReminderInfos> getReminderInfos(RepositoryEntryRef entry) {
 		return reminderDao.getReminderInfos(entry);
@@ -152,6 +177,45 @@ public class ReminderServiceImpl implements ReminderService {
 		return (ReminderRules)ruleXStream.fromXML(rulesXml);
 	}
 	
+	@Override
+	public void exportReminders(RepositoryEntry entry, File fExportedDataDir) {
+		List<Reminder> reminders = reminderDao.getReminders(entry);
+		if(reminders.size() > 0) {
+			try (OutputStream fOut = new FileOutputStream(new File(fExportedDataDir, REMINDERS_XML))) {
+				ImportExportReminders exportReminders = new ImportExportReminders();
+				for(Reminder reminder:reminders) {
+					ImportExportReminder exportReminder = new ImportExportReminder(reminder);
+					exportReminders.getReminders().add(exportReminder);
+				}
+				ruleXStream.toXML(exportReminders, fOut);
+			} catch(Exception e) {
+				log.error("", e);
+			}
+		}
+	}
+
+	@Override
+	public List<Reminder> importRawReminders(Identity creator, RepositoryEntry newEntry, File fExportedDataDir) {
+		File reminderFile = new File(fExportedDataDir, REMINDERS_XML);
+		List<Reminder> reminders = new ArrayList<>();
+		if(reminderFile.exists()) {
+			try(InputStream in = new FileInputStream(reminderFile)) {
+				ImportExportReminders importReminders = (ImportExportReminders)ruleXStream.fromXML(in);
+				List<ImportExportReminder> importReminderList = importReminders.getReminders();
+				for(ImportExportReminder importReminder:importReminderList) {
+					Reminder reminder = reminderDao.createReminder(newEntry, creator);
+					reminder.setDescription(importReminder.getDescription());
+					reminder.setEmailBody(importReminder.getEmailBody());	
+					reminder.setConfiguration(importReminder.getConfiguration());
+					reminders.add(reminder);
+				}
+			} catch(Exception e) {
+				log.error("", e);
+			}
+		}
+		return reminders;
+	}
+
 	@Override
 	public void remindAll() {
 		Date now = new Date();
@@ -176,16 +240,19 @@ public class ReminderServiceImpl implements ReminderService {
 		MailContext context = new MailContextImpl("[RepositoryEntry:" + entry.getKey() + "]");
 		String subject = "Reminder";
 		String body = reminder.getEmailBody();
-		
-		MailBundle bundle = new MailBundle();
-		bundle.setContext(context);
-		bundle.setContactList(contactList);
-		bundle.setContent(subject, body);
-		
-		MailerResult result = mailManager.sendMessage(bundle);
-		List<Identity> failedIdentities = result.getFailedIdentites();
+		String metaId = UUID.randomUUID().toString();
+		String url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + entry.getKey();
+
+		MailerResult overviewResult = new MailerResult();
+		ReminderTemplate template = new ReminderTemplate(subject, body, url, entry);
+
 		for(Identity identityToRemind:identitiesToRemind) {
 			String status;
+			MailBundle bundle = mailManager.makeMailBundle(context, identityToRemind, template, null, metaId, overviewResult);
+			MailerResult result = mailManager.sendMessage(bundle);
+			overviewResult.append(result);
+			
+			List<Identity> failedIdentities = result.getFailedIdentites();
 			if(failedIdentities != null && failedIdentities.contains(identityToRemind)) {
 				status = "error";
 			} else {
@@ -193,6 +260,38 @@ public class ReminderServiceImpl implements ReminderService {
 			}
 			reminderDao.markAsSend(reminder, identityToRemind, status);
 		}
-		return result;
+		
+		return overviewResult;
+	}
+	
+	private class ReminderTemplate extends MailTemplate {
+		
+		private final String url;
+		private final RepositoryEntry entry;
+		
+		public ReminderTemplate(String subjectTemplate, String bodyTemplate, String url, RepositoryEntry entry) {
+			super(subjectTemplate, bodyTemplate, null);
+			this.url = url;
+			this.entry = entry;
+		}
+
+		@Override
+		public void putVariablesInMailContext(VelocityContext vContext, Identity recipient) {
+			User user = recipient.getUser();
+			vContext.put("firstname", user.getProperty(UserConstants.FIRSTNAME, null));
+			vContext.put(UserConstants.FIRSTNAME, user.getProperty(UserConstants.FIRSTNAME, null));
+			vContext.put("lastname", user.getProperty(UserConstants.LASTNAME, null));
+			vContext.put(UserConstants.LASTNAME, user.getProperty(UserConstants.LASTNAME, null));
+			String fullName = userManager.getUserDisplayName(recipient);
+			vContext.put("fullname", fullName);
+			vContext.put("fullName", fullName);
+			vContext.put("login", user.getProperty(UserConstants.EMAIL, null));
+			// Put variables from greater context
+			if(entry != null) {
+				vContext.put("courseurl", url);
+				vContext.put("coursename", entry.getDisplayname());
+				vContext.put("coursedescription", entry.getDescription());
+			}
+		}
 	}
 }
diff --git a/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java b/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java
new file mode 100644
index 0000000000000000000000000000000000000000..48b21dc393791124f8605089207918b4bd9d44cf
--- /dev/null
+++ b/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java
@@ -0,0 +1,74 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.reminder.model;
+
+import java.io.Serializable;
+
+import org.olat.modules.reminder.Reminder;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ImportExportReminder implements Serializable {
+
+	private static final long serialVersionUID = -6548172969534189234L;
+	
+	private String description;
+	private String configuration;
+	private String emailBody;
+	
+	public ImportExportReminder() {
+		//
+	}
+	
+	public ImportExportReminder(Reminder reminder) {
+		description = reminder.getDescription();
+		configuration = reminder.getConfiguration();
+		emailBody = reminder.getEmailBody();
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+	public String getConfiguration() {
+		return configuration;
+	}
+	
+	public void setConfiguration(String configuration) {
+		this.configuration = configuration;
+	}
+	
+	public String getEmailBody() {
+		return emailBody;
+	}
+	
+	public void setEmailBody(String emailBody) {
+		this.emailBody = emailBody;
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/reminder/model/ImportExportReminders.java b/src/main/java/org/olat/modules/reminder/model/ImportExportReminders.java
new file mode 100644
index 0000000000000000000000000000000000000000..434e29af01ca048bc2777f9f6fc44b891fdfe2dd
--- /dev/null
+++ b/src/main/java/org/olat/modules/reminder/model/ImportExportReminders.java
@@ -0,0 +1,51 @@
+/**
+ * <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.reminder.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 
+ * Initial date: 12.05.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ImportExportReminders implements Serializable {
+
+	private static final long serialVersionUID = -7591298715271752339L;
+	private List<ImportExportReminder> reminders;
+
+	public ImportExportReminders() {
+		//
+	}
+
+	public List<ImportExportReminder> getReminders() {
+		if(reminders == null) {
+			reminders = new ArrayList<>();
+		}
+		return reminders;
+	}
+
+	public void setReminders(List<ImportExportReminder> reminders) {
+		this.reminders = reminders;
+	}
+}
diff --git a/src/main/java/org/olat/modules/reminder/model/ReminderRuleImpl.java b/src/main/java/org/olat/modules/reminder/model/ReminderRuleImpl.java
index 78f30480e5bf848ca634f67e3546a20c80a97c1b..96050d9e65cbb1f357726c89f974735dc9f643aa 100644
--- a/src/main/java/org/olat/modules/reminder/model/ReminderRuleImpl.java
+++ b/src/main/java/org/olat/modules/reminder/model/ReminderRuleImpl.java
@@ -75,4 +75,15 @@ public class ReminderRuleImpl implements ReminderRule {
 	public void setRightUnit(String rightUnit) {
 		this.rightUnit = rightUnit;
 	}
+	
+	@Override
+	public ReminderRule clone() {
+		ReminderRuleImpl clone = new ReminderRuleImpl();
+		clone.type = type;
+		clone.leftOperand = leftOperand;
+		clone.operator = operator;
+		clone.rightOperand = rightOperand;
+		clone.rightUnit = rightUnit;
+		return clone;
+	}
 }
diff --git a/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java
index c869ec73b6a7c79904f614efac3a72a4d47043ea..f2fbcbb696c6da301c93e0f62ecaed31d2b8cacd 100644
--- a/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java
@@ -25,9 +25,11 @@ import java.util.List;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.group.BusinessGroupRef;
 import org.olat.group.manager.BusinessGroupRelationDAO;
 import org.olat.group.model.BusinessGroupRefImpl;
+import org.olat.group.model.BusinessGroupReference;
 import org.olat.modules.reminder.IdentitiesProviderRuleSPI;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.RuleEditorFragment;
@@ -63,6 +65,25 @@ public class BusinessGroupRoleRuleSPI implements IdentitiesProviderRuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new BusinessGroupRoleEditor(rule, entry);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		ReminderRuleImpl clone = (ReminderRuleImpl)rule.clone();
+		String groupKey = clone.getRightOperand();
+		
+		boolean found = false;
+		if(StringHelper.isLong(groupKey)) {
+			Long key = Long.parseLong(groupKey);
+			for(BusinessGroupReference ref:envMapper.getGroups()) {
+				if(key.equals(ref.getOriginalKey()) && ref.getKey() != null) {
+					clone.setRightOperand(ref.getKey().toString());
+					found = true;
+				}
+			}
+		}
+		
+		return found ? clone : null;
+	}
 
 	@Override
 	public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule) {
diff --git a/src/main/java/org/olat/modules/reminder/rule/CourseEnrollmentDateRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/CourseEnrollmentDateRuleSPI.java
index aa8915d60b2513162c010397366ffa1915a37dc1..42913e8d3449235eaa515573355c710169ea33c9 100644
--- a/src/main/java/org/olat/modules/reminder/rule/CourseEnrollmentDateRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/CourseEnrollmentDateRuleSPI.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.olat.core.id.Identity;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.manager.ReminderDAO;
 import org.olat.repository.RepositoryEntry;
@@ -46,6 +47,11 @@ public class CourseEnrollmentDateRuleSPI extends AbstractLaunchDateRuleSPI {
 	public String getLabelI18nKey() {
 		return "rule.course.enrollment.date";
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	protected Map<Long, Date> getLaunchDates(ReminderRule rule, RepositoryEntry entry, List<Identity> identities) {
diff --git a/src/main/java/org/olat/modules/reminder/rule/DateRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/DateRuleSPI.java
index 40cdf3c009b89b1fcad5ef7d9eea46ec79b25166..f2f72b8f2f455c41a404d9325592bbfd3af97302 100644
--- a/src/main/java/org/olat/modules/reminder/rule/DateRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/DateRuleSPI.java
@@ -26,6 +26,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.RuleEditorFragment;
 import org.olat.modules.reminder.RuleSPI;
@@ -62,6 +63,11 @@ public class DateRuleSPI implements RuleSPI {
 		return new DateRuleEditor(rule);
 	}
 	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
+	
 	public boolean evaluate(ReminderRule rule) {
 		boolean allOk = true;
 		
diff --git a/src/main/java/org/olat/modules/reminder/rule/InitialCourseLaunchRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/InitialCourseLaunchRuleSPI.java
index 33a8951b8d9095bf2e67e8457c6e72554997a9a0..49c7ae721495ca2e258deab013b2466b87f72845 100644
--- a/src/main/java/org/olat/modules/reminder/rule/InitialCourseLaunchRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/InitialCourseLaunchRuleSPI.java
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.olat.core.id.Identity;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -46,6 +47,11 @@ public class InitialCourseLaunchRuleSPI extends AbstractLaunchDateRuleSPI {
 	public String getLabelI18nKey() {
 		return "rule.initial.course.launch.date";
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	protected Map<Long, Date> getLaunchDates(ReminderRule rule, RepositoryEntry entry, List<Identity> identities) {
diff --git a/src/main/java/org/olat/modules/reminder/rule/RecentCourseLaunchRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/RecentCourseLaunchRuleSPI.java
index 52754bfc237488a48926bd055674549efece2895..ac2944ef155be7ee74c19dfe44ebc51d203d3e49 100644
--- a/src/main/java/org/olat/modules/reminder/rule/RecentCourseLaunchRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/RecentCourseLaunchRuleSPI.java
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.olat.core.id.Identity;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -51,6 +52,11 @@ public class RecentCourseLaunchRuleSPI extends AbstractLaunchDateRuleSPI {
 	public String getCategory() {
 		return "general";
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	protected Map<Long, Date> getLaunchDates(ReminderRule rule, RepositoryEntry entry, List<Identity> identities) {
diff --git a/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java
index 236ef2f3f0d1f0fbad62e20c472f577d7ee3f401..86c52908a8149e73774260625f1d119599acacca 100644
--- a/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java
@@ -25,6 +25,7 @@ import java.util.List;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.IdentitiesProviderRuleSPI;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.RuleEditorFragment;
@@ -62,6 +63,11 @@ public class RepositoryEntryRoleRuleSPI implements IdentitiesProviderRuleSPI  {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new RepositoryEntryRoleEditor(rule);
 	}
+	
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
 
 	@Override
 	public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule) {
diff --git a/src/main/java/org/olat/modules/reminder/rule/UserPropertyRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/UserPropertyRuleSPI.java
index de037aea84f234c4a8f5a42149130d0c9c77781b..69017853fb30e9c602af82eebe74c6da53a91b06 100644
--- a/src/main/java/org/olat/modules/reminder/rule/UserPropertyRuleSPI.java
+++ b/src/main/java/org/olat/modules/reminder/rule/UserPropertyRuleSPI.java
@@ -20,6 +20,7 @@
 package org.olat.modules.reminder.rule;
 
 import org.olat.core.id.Identity;
+import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.modules.reminder.ReminderRule;
 import org.olat.modules.reminder.RuleEditorFragment;
 import org.olat.modules.reminder.RuleSPI;
@@ -53,7 +54,12 @@ public class UserPropertyRuleSPI implements RuleSPI {
 	public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) {
 		return new UserPropertyEditor(rule);
 	}
-	
+
+	@Override
+	public ReminderRule clone(ReminderRule rule, CourseEnvironmentMapper envMapper) {
+		return rule.clone();
+	}
+
 	public boolean accept(ReminderRule rule, Identity identity) {
 		boolean allOk = false;
 		if(rule instanceof ReminderRuleImpl) {
diff --git a/src/main/java/org/olat/modules/reminder/ui/ReminderAdminController.java b/src/main/java/org/olat/modules/reminder/ui/ReminderAdminController.java
index 038f39c427e03ce7853fff412f7293a8a1252048..b4ac4b89960e5fa814a4587fd85a93bedbfc7e0f 100644
--- a/src/main/java/org/olat/modules/reminder/ui/ReminderAdminController.java
+++ b/src/main/java/org/olat/modules/reminder/ui/ReminderAdminController.java
@@ -25,9 +25,9 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.AbstractComponent;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.elements.IntegerElement;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
@@ -60,7 +60,7 @@ public class ReminderAdminController extends FormBasicController {
 	};
 	
 	private MultipleSelectionElement enableEl;
-	private IntegerElement hoursEl, minutesEl;
+	private TextElement hoursEl, minutesEl;
 	private SingleSelection timezoneEl;
 	private SingleSelection intervalEl;
 	private FormLayoutContainer timeLayout;
@@ -130,12 +130,17 @@ public class ReminderAdminController extends FormBasicController {
 		timeLayout.setRootForm(mainForm);
 		formLayout.add(timeLayout);
 		timeLayout.setLabel("default.send.time", null);
-		hoursEl = uifactory.addIntegerElement("hours", null, hour, timeLayout);
+		
+		String hourStr = (hour < 10 ? "0" : "") + hour;
+		hoursEl = uifactory.addTextElement("hours", null, 2, hourStr, timeLayout);
 		hoursEl.setDisplaySize(2);
-		((AbstractComponent)hoursEl.getComponent()).setDomReplacementWrapperRequired(false);
-		minutesEl = uifactory.addIntegerElement("minutes", null, minute, timeLayout);
+		hoursEl.setDomReplacementWrapperRequired(false);
+
+		String minuteStr = (minute < 10 ? "0" : "") + minute;
+		minutesEl = uifactory.addTextElement("minutes", null, 2, minuteStr, timeLayout);
 		minutesEl.setDisplaySize(2);
-		((AbstractComponent)minutesEl.getComponent()).setDomReplacementWrapperRequired(false);
+		minutesEl.setDomReplacementWrapperRequired(false);
+		
 		String[] timezoneKeys = TimeZone.getAvailableIDs();
 		String[] timezoneValues = new String[timezoneKeys.length];
 		for(int i=timezoneKeys.length; i-->0; ) {
@@ -177,6 +182,45 @@ public class ReminderAdminController extends FormBasicController {
 		super.formInnerEvent(ureq, source, event);
 	}
 
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		hoursEl.clearError();
+		minutesEl.clearError();
+		boolean enabled = enableEl.isAtLeastSelected(1);
+		if(enabled) {
+			allOk &= validate(hoursEl, 23);
+			allOk &= validate(minutesEl, 59);
+		}
+		
+		return allOk & super.validateFormLogic(ureq);
+	}
+	
+	private boolean validate(TextElement textEl, int max) {
+		boolean allOk = true;
+		
+		String value = textEl.getValue();
+		if(StringHelper.containsNonWhitespace(value)) {
+			try {
+				int val = Integer.parseInt(value);
+				if(val < 0) {
+					textEl.setErrorKey("text.element.error.minvalue", new String[]{ "0" });
+				} else if(val > max) {
+					textEl.setErrorKey("text.element.error.maxvalue", new String[]{ Integer.toString(max) });
+				}
+			} catch (NumberFormatException e) {
+				textEl.setErrorKey("integer.element.int.error", null);
+				allOk &= false;
+			}
+		} else {
+			textEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		return allOk;
+	}
+
 	@Override
 	protected void formOK(UserRequest ureq) {
 		boolean enabled = enableEl.isAtLeastSelected(1);
@@ -185,9 +229,9 @@ public class ReminderAdminController extends FormBasicController {
 		if(enabled) {
 			String interval = intervalEl.getSelectedKey();
 
-			int hours = hoursEl.getIntValue();
-			int minutes = minutesEl.getIntValue();
-			String sendTime = hours + ":" + minutes;
+			String hoursStr = hoursEl.getValue();
+			String minutesStr = minutesEl.getValue();
+			String sendTime = Integer.parseInt(hoursStr) + ":" + Integer.parseInt(minutesStr);
 			reminderModule.setScheduler(interval, sendTime);
 			
 			if(timezoneEl.isOneSelected()) {
diff --git a/src/main/java/org/olat/modules/reminder/ui/_content/time.html b/src/main/java/org/olat/modules/reminder/ui/_content/time.html
index e2dc75b5552a37494230777f72ec5fdea2dc2093..48bf8fed10f27e5c4bab3a4e536bd774a8e7ff6c 100644
--- a/src/main/java/org/olat/modules/reminder/ui/_content/time.html
+++ b/src/main/java/org/olat/modules/reminder/ui/_content/time.html
@@ -1,3 +1,7 @@
-<div class='form-inline'>
-	$r.render("hours") <span class="form-control-static">:</span> $r.render("minutes") $r.render("timezone")
-</div>
\ No newline at end of file
+<div class='form-inline'>$r.render("hours") <span class="form-control-static">:</span> $r.render("minutes") $r.render("timezone")</div>
+#if($f.hasError("hours"))
+	<br/>$r.render("hours_ERROR")
+#end
+#if($f.hasError("minutes"))
+	<br/>$r.render("minutes_ERROR")
+#end
\ No newline at end of file
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 5c51a614e73a506bf8a953736a542a9bd699230a..d017a6aff4aff10297880d7aa620ad8ee85fe402 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
@@ -1,24 +1,24 @@
 #Thu Apr 09 21:54:06 CEST 2015
-admin.menu.title=Course reminders
-admin.menu.title.alt=Course reminders
-ago=ago
-default.send.time=Default time to send reminders
-enable.reminders=Activate course reminders
-enable.sms.reminders=SMS remidners
+admin.menu.title=Kurserinnerungen
+admin.menu.title.alt=Kurserinnerungen
+ago=her
+default.send.time=Standard Sendezeit für Erinnerungen
+enable.reminders=Kurserinnerungen einschalten
+enable.sms.reminders=SMS Erinnerungen
 error.group.not.found=Gruppe existiert nicht in diesem Kurs
 interval.24=1 Mal pro Tag
 interval.12=2 Mal pro Tag
 interval.8=3 Mal pro Tag
 interval.6=4 Mal pro Tag
-interval.4=Jede vier Stunde
-interval.2=Jede zwei Stunde
+interval.4=Alle vier Stunden
+interval.2=Alle zwei Stunden
 interval.1=Jede Stunde
-reminder.admin.title=Course reminders
-rule.after.date=Nach dem Datum
-rule.course.enrollment.date=Enrollment date
-rule.course.role=Course role
-rule.group.member=Gruppen Teilnehmer
-rule.initial.course.launch.date=Initial course launch date
-rule.recent.course.launch.date=Recent course launch date
-rule.user.property=User property
+reminder.admin.title=Kurserinnerungen
+rule.after.date=Nach Datum
+rule.course.enrollment.date=Einschreibedatum
+rule.course.role=Kursrolle
+rule.group.member=Gruppenteilnehmer
+rule.initial.course.launch.date=Erster Kursbesuch
+rule.recent.course.launch.date=Letzter Kursbesuch
+rule.user.property=Benutzereigenschaft
 
diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties
index 86a11b81a50d5783b0b76e3a81688b943fbbc5ab..c133b55888ccea670cdf32a53a45f60726fe98ac 100644
--- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties
@@ -1,16 +1,16 @@
 #Thu Apr 09 21:54:18 CEST 2015
 admin.menu.title=Course reminders
 admin.menu.title.alt=Course reminders
-ago=ago
+ago=since
 default.send.time=Default time to send reminders
 enable.reminders=Activate course reminders
-enable.sms.reminders=SMS remidners
+enable.sms.reminders=SMS reminders
 error.group.not.found=Group doesn't exist within this course
 interval=Interval
-interval.24=1 time per day
-interval.12=2 time per day
-interval.8=3 time per day
-interval.6=4 time per day
+interval.24=Once a day
+interval.12=Twice a day
+interval.8=3 times a day
+interval.6=4 times a day
 interval.4=Every 4 hours
 interval.2=Every 2 hours
 interval.1=Every hour
diff --git a/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml b/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
index 7964ac792d77fbdac6d68db174bc64418f5f0ffb..4c71338f30167c6f4c624482396ef94b3bc89760 100644
--- a/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
+++ b/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
@@ -2,7 +2,6 @@
 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping>
 	<class name="org.olat.repository.model.RepositoryEntryShortImpl" table="o_repositoryentry" mutable="false">
-		<cache usage="transactional" />
 		<id name="key" column="repositoryentry_id" type="long" unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_ar.properties
index b74154b049914d948b1648e57b52cf284974d52d..2b27d07310bba8a3713de40ca48027adc02a0cea 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_ar.properties
@@ -363,6 +363,7 @@ table.subject.telPrivate=\u0631\u0642\u0645 \u0647\u0627\u062A\u0641 \u0627\u064
 table.subject.zipCode=\u0627\u0644\u0631\u0645\u0632 \u0627\u0644\u0628\u0631\u064A\u062F\u0649
 table.user.login=\u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
 title.prefix.closed=\u062A\u0645 \u0625\u063A\u0644\u0627\u0642\u0647
+tools=$\:table.header.actions
 tools.add.blog=\u0645\u062F\u0648\u0646\u0629
 tools.add.course=\u0645\u0642\u0631\u0631
 tools.add.cp=\u0645\u062D\u062A\u0648\u0649 \u062D\u0632\u0645\u0629 \u062A\u0639\u0644\u064A\u0645
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_bg.properties
index b7c5c59a917c9f0f375c060b0d2937638ffe535c..0756db6543c59b880a46b00aa128c08bf5d45a08 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_bg.properties
@@ -352,6 +352,7 @@ table.subject.telPrivate=\u0414\u043E\u043C\u0430\u0448\u0435\u043D \u0442\u0435
 table.subject.zipCode=\u041F\u043E\u0449\u0435\u043D\u0441\u043A\u0438 \u043A\u043E\u0434
 table.user.login=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435
 title.prefix.closed=\u0417\u0430\u0442\u0432\u043E\u0440\u0435\u043D
+tools=$\:table.header.actions
 tools.add.course=\u041A\u0443\u0440\u0441
 tools.add.cp=CP \u0443\u0447\u0435\u0431\u043D\u043E \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435
 tools.add.glossary=\u0420\u0435\u0447\u043D\u0438\u043A
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_cs.properties
index 5fbf6bf1aefa441d92888df0220823e0e81bf29f..0b64598f745dea24152b28e58a38ae6a3180ab8a 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_cs.properties
@@ -327,6 +327,7 @@ table.subject.telOffice=Telefon pr\u00E1ce
 table.subject.telPrivate=Telefon dom\u016F
 table.subject.zipCode=PS\u010C
 table.user.login=U\u017Eivatelsk\u00E9 jm\u00E9no
+tools=$\:table.header.actions
 tools.add.course=Kurz
 tools.add.cp=CP studijn\u00ED materi\u00E1l
 tools.add.glossary=Slovn\u00EDk
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_da.properties
index eb28e78afeb2e229fa35a9468340a383bdc0a9a1..0a39ef45aa33944a0d7de8cd6a8404f4d7c59db8 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_da.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_da.properties
@@ -272,6 +272,7 @@ table.subject.telOffice=Telefon arbejde
 table.subject.telPrivate=Telefon privat
 table.subject.zipCode=Postnummer
 table.user.login=Brugernavn
+tools=$\:table.header.actions
 tools.add.course=Kursus
 tools.add.cp=CP l\u00E6ringsindhold
 tools.add.glossary=Ordliste
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 cc18bc3d816a9b4f83291c03174fe7063e4d4856..23322108b78cae8b468a4a09f1742eb2a3a15090 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
@@ -619,7 +619,7 @@ table.switch.list=Liste
 table.switch.table=Tabelle
 table.user.login=Benutzername
 title.prefix.closed=beendet
-tools=Werkzeuge und Aktionen
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Kurs
 tools.add.cp=CP-Lerninhalt
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_el.properties
index 9b35dd5dde9cb60d86dea7fb38f1ae2445a7d411..180e52fbb7d486cb4bf4f5d871168774915c1177 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_el.properties
@@ -376,6 +376,7 @@ table.subject.telPrivate=\u03A4\u03B7\u03BB\u03AD\u03C6\u03C9\u03BD\u03BF \u03C0
 table.subject.zipCode=\u03A4\u03B1\u03C7\u03C5\u03B4\u03C1\u03BF\u03BC\u03B9\u03BA\u03CC\u03C2 \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1\u03C2
 table.user.login=\u038C\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
 title.prefix.closed=\u03BA\u03BB\u03B5\u03B9\u03C3\u03C4\u03CC
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=\u039C\u03AC\u03B8\u03B7\u03BC\u03B1
 tools.add.cp=\u03A0\u03B5\u03C1\u03B9\u03B5\u03C7\u03CC\u03BC\u03B5\u03BD\u03BF \u03BC\u03AC\u03B8\u03B7\u03C3\u03B7\u03C2 CP
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 6f1f7681487d9f2d8e80e38a168e0073fc6d0ca8..c2a778f0adaa23cb24828619d5fe776383320704 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
@@ -618,7 +618,7 @@ table.switch.list=List
 table.switch.table=Table
 table.user.login=User name
 title.prefix.closed=closed
-tools=Tools and actions
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Course
 tools.add.cp=CP learning content
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_es.properties
index 9dbb911d5b1468f000568913dead387ec015f6b7..90743485a0e17e3b40638ccbcc66083f97d1306f 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_es.properties
@@ -350,6 +350,7 @@ table.subject.telPrivate=N\u00B0 tel\u00E9fono privado
 table.subject.zipCode=C\u00F3digo postal
 table.user.login=Nombre de usuario
 title.prefix.closed=cerrado
+tools=$\:table.header.actions
 tools.add.course=Curso
 tools.add.cp=Contenido did\u00E1ctico CP
 tools.add.glossary=Glosario
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_et_EE.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_et_EE.properties
index ffd4a14e9e6295d958b405048f3b686afcb18058..445595d587b0b906054c6296c12471927772a818 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_et_EE.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_et_EE.properties
@@ -39,6 +39,7 @@ table.subject.street=T\u00E4nav
 table.subject.telMobile=Mobiiltelefon
 table.subject.zipCode=Postiindeks
 table.user.login=Kasutajanimi
+tools=$\:table.header.actions
 tools.add.glossary=S\u00F5nastik
 tools.add.survey=K\u00FCsimustik
 tools.add.test=Test
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_fa.properties
index b09fdec75255cf6cf157f70230f40e1708bb0e1d..638404dba629fc76c3edfe1deede1ffa9114f00b 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_fa.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_fa.properties
@@ -240,6 +240,7 @@ table.subject.telOffice=\u0634\u0645\u0627\u0631\u0647 \u062A\u0644\u0641\u0646
 table.subject.telPrivate=\u0634\u0645\u0627\u0631\u0647 \u062A\u0645\u0627\u0633 \u0634\u062E\u0635\u06CC 
 table.subject.zipCode=\u06A9\u062F \u0634\u0647\u0631 
 table.user.login=\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC 
+tools=$\:table.header.actions
 tools.add.course=\u062F\u0648\u0631\u0647 
 tools.add.cp=CP \u0645\u062D\u062A\u0648\u0627\u06CC \u0622\u0645\u0648\u0632\u0634\u06CC
 tools.add.header=\u0627\u0641\u0632\u0648\u062F\u0646
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties
index 3d0d28c907e0d09b6a0caca08244b6dfc4bd4323..ee8372076c353e62a529f134d92553918c1b3963 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties
@@ -612,7 +612,7 @@ table.switch.list=Liste
 table.switch.table=Table
 table.user.login=Nom d'utilisateur
 title.prefix.closed=termin\u00E9
-tools=Outils et actions
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Cours
 tools.add.cp=Contenu did. CP
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties
index a37f88c892ac96a56704c1b7f5f9dfac21bc21f7..47cdb2be1217b60bff90a0d6a0b2b826e532820e 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties
@@ -381,6 +381,7 @@ table.subject.telPrivate=Telefono privato
 table.subject.zipCode=Codice di avviamento postale
 table.user.login=Nome d'utente
 title.prefix.closed=terminato
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Corso
 tools.add.cp=Contenuto CP
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_jp.properties
index ae6d7464813378d434549073e8bb41d5f539bd14..8299a519fb22c3fdc3b122e72769b051e42f8f9e 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_jp.properties
@@ -252,6 +252,7 @@ table.header.typeimg=\u30BF\u30A4\u30D7
 table.preview=<i class='o_icon o_icon-lg o_icon_preview' title='$\:preview.header'> </i>
 table.select=<i class='o_icon o_icon-lg o_icon_select'> </i>
 table.subject.institutionalUserIdentifier=\u30A4\u30F3\u30B9\u30C6\u30A3\u30C6\u30E5\u30FC\u30B7\u30E7\u30F3ID (\u767B\u9332\u756A\u53F7)
+tools=$\:table.header.actions
 tools.add.blog=\u30D6\u30ED\u30B0
 tools.add.course=\u30B3\u30FC\u30B9
 tools.add.cp=CP\u5B66\u7FD2\u30B3\u30F3\u30C6\u30F3\u30C4
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_lt.properties
index 73360d5778183cb50c7ad08efa686e0d73119985..7c055175c013660b264eb6d81ef01c897e35ad7f 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_lt.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_lt.properties
@@ -288,6 +288,7 @@ table.subject.telOffice=Telefono nr. (darbo)
 table.subject.telPrivate=Telefono nr. (nam\u0173)
 table.subject.zipCode=Pa\u0161to indeksas
 table.user.login=Vartotojo vardas
+tools=$\:table.header.actions
 tools.add.course=Kursas
 tools.add.cp=CP mokymosi turinys
 tools.add.header=Prid\u0117ti
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_nl_NL.properties
index 1ae41c946566899ee3c267c14d36d053b24b5da0..16523174b194a41bfa1423b2d9b7a971892b8791 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_nl_NL.properties
@@ -381,6 +381,7 @@ table.subject.telPrivate=Telefoonnummer (priv\u00E9)
 table.subject.zipCode=Postcode
 table.user.login=Gebruikersnaam
 title.prefix.closed=Be\u00EBindigd
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Cursus
 tools.add.cp=CP-leerinhoud
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties
index eb953d5befcacafcec4fcd46a17cfc9d5748abbe..931b59c6c3bf84f506c614d302e3975495f0b16e 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties
@@ -429,6 +429,7 @@ table.subject.telPrivate=Numer stacjonarnego telefonu prywatnego
 table.subject.zipCode=Kod
 table.user.login=Nazwa u\u017Cytkownika
 title.prefix.closed=zamkni\u0119ty
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Kurs
 tools.add.cp=Pakiet CP
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties
index 5348e7950529a64ed346f5f200dc499f0db29de1..51b4dd2e83784067c23485c46921434de38ae9bd 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties
@@ -611,7 +611,7 @@ table.switch.list=Lista
 table.switch.table=Tabela
 table.user.login=Nome do usu\u00E1rio
 title.prefix.closed=Fechado
-tools=Ferramentas e a\u00E7\u00F5es
+tools=$\:table.header.actions
 tools.add.blog=Blog
 tools.add.course=Curso
 tools.add.cp=M\u00F3dulo IMS-CP
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_PT.properties
index 3cdb7af3f786dc997add9f279837e3d1f0a50ba6..3e0f8d1c542b53d9454f63268ce7fd2ce92114fd 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_PT.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_PT.properties
@@ -323,6 +323,7 @@ table.subject.telOffice=Telefone comercial
 table.subject.telPrivate=Telefone residencial
 table.subject.zipCode=CEP
 table.user.login=Nome do usu\u00E1rio
+tools=$\:table.header.actions
 tools.add.course=Curso
 tools.add.cp=M\u00F3dulo IMS-CP
 tools.add.glossary=Gloss\u00E1rio
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_ru.properties
index 0703b0fe547fbdd6067ce52806298021baf3e347..e3d040ac48dac9dedcc472232bcb4e0555e939fb 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_ru.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_ru.properties
@@ -299,6 +299,7 @@ table.subject.telPrivate=\u0414\u043E\u043C\u0430\u0448\u043D\u0438\u0439 \u0442
 table.subject.zipCode=\u0418\u043D\u0434\u0435\u043A\u0441 \u043F\u043E\u0447\u0442\u043E\u0432\u043E\u0433\u043E \u043E\u0442\u0434\u0435\u043B\u0435\u043D\u0438\u044F
 table.user.login=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
 title.prefix.closed=\u0437\u0430\u043A\u043E\u043D\u0447\u0435\u043D
+tools=$\:table.header.actions
 tools.add.course=\u041A\u0443\u0440\u0441
 tools.add.cp=\u0423\u0447\u0435\u0431\u043D\u043E\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u043D\u0438\u0435 CP
 tools.add.glossary=\u0421\u043B\u043E\u0432\u0430\u0440\u044C
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_sq.properties
index 2a0d088858317421c8fefc96316abfdba07951a9..6195c10fbe8f9ae0dd1e444a8f4daa12be473600 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_sq.properties
@@ -273,6 +273,7 @@ table.subject.telOffice=Nr. telefonit zyre
 table.subject.telPrivate=Nr. telefonit privat
 table.subject.zipCode=Kodi postal
 table.user.login=Emri i shfryt\u00EBzuesit
+tools=$\:table.header.actions
 tools.add.course=Kurs
 tools.add.cp=CP p\u00EBrmbajtje m\u00EBsimi
 tools.add.glossary=P\u00EBrmbledhje
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties
index 315a1f888d5adc1141ecf38d012f6dbc22fa4702..82d32ffc28406e0e0ee6dde6c1ae89480013998f 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties
@@ -488,7 +488,7 @@ table.switch.list=\u5217\u8868
 table.switch.table=\u8868\u683C
 table.user.login=\u7528\u6237\u540D\u79F0
 title.prefix.closed=\u5173\u95ED
-tools=\u5DE5\u5177\u548C\u52A8\u4F5C
+tools=$\:table.header.actions
 tools.add.blog=\u535A\u5BA2
 tools.add.course=\u8BFE\u7A0B
 tools.add.cp=CP\u8BFE\u4EF6
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_TW.properties
index e47b9e715a47fee8214bf06a013b823f025b19fc..32ad8c5ed988ebbd8a5e761398b5cab888ef7b7e 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_TW.properties
@@ -313,6 +313,7 @@ table.subject.telPrivate=\u4F4F\u5B85\u96FB\u8A71
 table.subject.zipCode=\u90F5\u905E\u5340\u865F
 table.user.login=\u4F7F\u7528\u8005\u540D\u7A31
 title.prefix.closed=\u95DC\u9589\u7684
+tools=$\:table.header.actions
 tools.add.blog=\u90E8\u843D\u683C
 tools.add.course=\u8AB2\u7A0B
 tools.add.cp=CP \u5B78\u7FD2\u5167\u5BB9
diff --git a/src/main/java/org/olat/repository/handlers/BlogHandler.java b/src/main/java/org/olat/repository/handlers/BlogHandler.java
index 5aad2425bea51f553f34566d1cfedfd9404c93f6..989d07fd05c79b21cc387734ed37af68b2dcc373 100644
--- a/src/main/java/org/olat/repository/handlers/BlogHandler.java
+++ b/src/main/java/org/olat/repository/handlers/BlogHandler.java
@@ -118,7 +118,7 @@ public class BlogHandler implements RepositoryHandler {
 	}
 
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		FeedManager.getInstance().copy(sourceResource, targetResource);
diff --git a/src/main/java/org/olat/repository/handlers/CourseHandler.java b/src/main/java/org/olat/repository/handlers/CourseHandler.java
index e7859d63f0d2236078ef8a216d3918aa4c980691..66d898da5f05abe522903e04b2089b144f000d6e 100644
--- a/src/main/java/org/olat/repository/handlers/CourseHandler.java
+++ b/src/main/java/org/olat/repository/handlers/CourseHandler.java
@@ -33,6 +33,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.util.List;
 import java.util.Locale;
 import java.util.UUID;
 
@@ -94,6 +95,12 @@ import org.olat.fileresource.types.GlossaryResource;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.fileresource.types.SharedFolderFileResource;
 import org.olat.modules.glossary.GlossaryManager;
+import org.olat.modules.reminder.Reminder;
+import org.olat.modules.reminder.ReminderModule;
+import org.olat.modules.reminder.ReminderRule;
+import org.olat.modules.reminder.ReminderService;
+import org.olat.modules.reminder.RuleSPI;
+import org.olat.modules.reminder.model.ReminderRules;
 import org.olat.modules.sharedfolder.SharedFolderManager;
 import org.olat.repository.ErrorList;
 import org.olat.repository.RepositoryEntry;
@@ -290,6 +297,9 @@ public class CourseHandler implements RepositoryHandler {
 			re = imp.importContent(re, getMediaContainer(re));
 		}
 		
+		//import reminders
+		importReminders(re, fImportBaseDirectory, envMapper, initialAuthor);
+		
 		//clean up export folder
 		cleanExportAfterImport(fImportBaseDirectory);
 		
@@ -380,6 +390,29 @@ public class CourseHandler implements RepositoryHandler {
 		}
 	}
 	
+	private void importReminders(RepositoryEntry re, File fImportBaseDirectory, CourseEnvironmentMapper envMapper, Identity initialAuthor) {
+		ReminderModule reminderModule = CoreSpringFactory.getImpl(ReminderModule.class);
+		ReminderService reminderService = CoreSpringFactory.getImpl(ReminderService.class);
+		List<Reminder> reminders = reminderService.importRawReminders(initialAuthor, re, fImportBaseDirectory);
+		if(reminders.size() > 0) {
+			for(Reminder reminder:reminders) {
+				ReminderRules clonedRules = new ReminderRules();
+				String configuration = reminder.getConfiguration();
+				ReminderRules rules = reminderService.toRules(configuration);
+				for(ReminderRule rule:rules.getRules()) {
+					RuleSPI ruleSpi = reminderModule.getRuleSPIByType(rule.getType());
+					if(ruleSpi != null) {
+						ReminderRule clonedRule = ruleSpi.clone(rule, envMapper);
+						clonedRules.getRules().add(clonedRule);
+					}
+				}
+				String convertedConfiguration = reminderService.toXML(clonedRules);
+				reminder.setConfiguration(convertedConfiguration);
+				reminderService.save(reminder);
+			}
+		}
+	}
+	
 	private void markDirtyNewRecursively(CourseEditorTreeNode editorRootNode) {
 		editorRootNode.setDirty(true);
 		editorRootNode.setNewnode(true);
@@ -391,7 +424,7 @@ public class CourseHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		final OLATResource sourceResource = source.getOlatResource();
 		final OLATResource targetResource = target.getOlatResource();
 		
@@ -414,8 +447,35 @@ public class CourseHandler implements RepositoryHandler {
 		course = CourseFactory.loadCourse(cgm.getCourseResource());
 		course.postCopy(envMapper, sourceCourse);
 		
+		cloneReminders(author, envMapper, source, target);
+		
 		return target;
 	}
+	
+	private void cloneReminders(Identity author, CourseEnvironmentMapper envMapper, RepositoryEntry source, RepositoryEntry target) {
+		ReminderModule reminderModule = CoreSpringFactory.getImpl(ReminderModule.class);
+		ReminderService reminderService = CoreSpringFactory.getImpl(ReminderService.class);
+		List<Reminder> reminders = reminderService.getReminders(source);
+		
+		for(Reminder reminder:reminders) {
+			String configuration = reminder.getConfiguration();
+			ReminderRules rules = reminderService.toRules(configuration);
+			ReminderRules clonedRules = new ReminderRules();
+			for(ReminderRule rule:rules.getRules()) {
+				RuleSPI ruleSpi = reminderModule.getRuleSPIByType(rule.getType());
+				if(ruleSpi != null) {
+					ReminderRule clonedRule = ruleSpi.clone(rule, envMapper);
+					clonedRules.getRules().add(clonedRule);
+				}
+			}
+
+			Reminder clonedReminder = reminderService.createReminder(target, author);
+			clonedReminder.setDescription(reminder.getDescription());
+			clonedReminder.setEmailBody(reminder.getEmailBody());
+			clonedReminder.setConfiguration(reminderService.toXML(clonedRules));
+			reminderService.save(clonedReminder);
+		}
+	}
 
 	@Override
 	public String getSupportedType() {
diff --git a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
index bcd22dfa07bea7107eae5a56322ed41085c3d634..c864bdce0771e163a7074b3f5b376a6de7258eea 100644
--- a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
+++ b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
@@ -130,7 +130,7 @@ public class GlossaryHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource).getBasefile();
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index bf28e2e1097136e1b29c400eb6761b957f74edb4..952e8cc76401b606cc0e3d1814788d8ad4b9f224 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -138,7 +138,7 @@ public class ImsCPHandler extends FileHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		final CPManager cpManager = CPManager.getInstance();
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
diff --git a/src/main/java/org/olat/repository/handlers/PodcastHandler.java b/src/main/java/org/olat/repository/handlers/PodcastHandler.java
index 2d29046bc89e7f76d417847c3c62f3af260b3a61..6513dc7dc23124bb169cb30e5cb4b3cafd532a2b 100644
--- a/src/main/java/org/olat/repository/handlers/PodcastHandler.java
+++ b/src/main/java/org/olat/repository/handlers/PodcastHandler.java
@@ -118,7 +118,7 @@ public class PodcastHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		FeedManager.getInstance().copy(sourceResource, targetResource);
diff --git a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
index 7031582cb6ad9f540cdb873d7bf92a2f32647406..fcf427f7e3c6b4acf0b806a774a68b51392d5a4a 100644
--- a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
+++ b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
@@ -139,7 +139,7 @@ public class PortfolioHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		
diff --git a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java
index 199b61c23b48e67dc021d5025b1473891ad708db..daeda3195e91257fd4c8c693c70334df08e9ef06 100644
--- a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java
+++ b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java
@@ -106,7 +106,7 @@ public interface RepositoryHandler {
 	 * @param target
 	 * @return
 	 */
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target);
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target);
 	
 	
 	
diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
index f70b8ce78d8ba656bf589f50b03fcce4bc125a6d..2db8c9c36e4fce711b92feeceb013c97c4bf075d 100644
--- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
@@ -114,7 +114,7 @@ public class SCORMCPHandler extends FileHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		final ScormMainManager scormManager = ScormMainManager.getInstance();
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
diff --git a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
index 2c10db3e56827fe69be2d01c3932f8dcbef07e61..c03463f473adfcd380eafb3b6f125547196030d9 100644
--- a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
@@ -116,7 +116,7 @@ public class SharedFolderHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource).getBasefile();
diff --git a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
index 65a896caf260923b9f3d7508f4b5354b98dd6067..f211701ca366056a67b2f109ca2844c3bddbed8a 100644
--- a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
+++ b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
@@ -179,7 +179,7 @@ public class WebDocumentHandler extends FileHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		OLATResource sourceResource = source.getOlatResource();
 		OLATResource targetResource = target.getOlatResource();
 		File sourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(sourceResource).getBasefile();
diff --git a/src/main/java/org/olat/repository/handlers/WikiHandler.java b/src/main/java/org/olat/repository/handlers/WikiHandler.java
index e3d6d179eb5e643556cbf86bace94d95441e8445..92d0869acf73d0b274ca3cf1e729799bf9e79935 100644
--- a/src/main/java/org/olat/repository/handlers/WikiHandler.java
+++ b/src/main/java/org/olat/repository/handlers/WikiHandler.java
@@ -145,7 +145,7 @@ public class WikiHandler implements RepositoryHandler {
 	}
 	
 	@Override
-	public RepositoryEntry copy(RepositoryEntry source, RepositoryEntry target) {
+	public RepositoryEntry copy(Identity author, RepositoryEntry source, RepositoryEntry target) {
 		final OLATResource sourceResource = source.getOlatResource();
 		final OLATResource targetResource = target.getOlatResource();
 		final FileResourceManager frm = FileResourceManager.getInstance();
diff --git a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java
index 3978977bff08bfb96f009d2e0be31a2000fe6f75..dc38e93f0a8ba69926389a2fa45bba8b89e95562 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java
@@ -214,7 +214,7 @@ public class RepositoryServiceImpl implements RepositoryService {
 		copyEntry = dbInstance.getCurrentEntityManager().merge(copyEntry);
 	
 		RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(sourceEntry);
-		copyEntry = handler.copy(sourceEntry, copyEntry);
+		copyEntry = handler.copy(author, sourceEntry, copyEntry);
 		
 		
 		//copy the image
diff --git a/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml b/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml
index b981971b3eb8d55aa597377d8e6dd1bbde4077ab..8943281bbea6ae6f72071c5698347f180d426a4b 100644
--- a/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml
+++ b/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml
@@ -6,8 +6,6 @@
 <hibernate-mapping default-lazy="false">
 
   <class name="org.olat.repository.model.CatalogEntryImpl" table="o_catentry">
-    
-	<cache usage="transactional" />
 
     <id name="key" column="id" type="long" unsaved-value="null">
       <generator class="hilo"/>
diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
index 9e4406023df1cd8ede3269a5d5c5344c3c6db41c..b8b2d68340c9af44e04faf8fbeeaccbb6f8fc45e 100644
--- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
+++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
@@ -41,8 +41,6 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.MainLayoutBasicController;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
-import org.olat.core.gui.control.generic.dtabs.DTab;
-import org.olat.core.gui.control.generic.dtabs.DTabs;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.Step;
 import org.olat.core.gui.control.generic.wizard.StepRunnerCallback;
@@ -50,8 +48,6 @@ import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
-import org.olat.core.id.context.BusinessControl;
-import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.HistoryPoint;
 import org.olat.core.id.context.StateEntry;
@@ -635,28 +631,8 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	
 	protected final void doClose(UserRequest ureq) {
 		// Now try to go back to place that is attacked to (optional) root back business path
-		if (launchedFromPoint != null && StringHelper.containsNonWhitespace(launchedFromPoint.getBusinessPath())
-				&& launchedFromPoint.getEntries() != null && launchedFromPoint.getEntries().size() > 0) {
-			BusinessControl bc = BusinessControlFactory.getInstance().createFromPoint(launchedFromPoint);
-			if(bc.hasContextEntry()) {
-				WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
-				try {
-					//make the resume secure. If something fail, don't generate a red screen
-					NewControllerFactory.getInstance().launch(ureq, bwControl);
-				} catch (Exception e) {
-					logError("Error while resuming with root level back business path::" + launchedFromPoint.getBusinessPath(), e);
-				}
-			}
-		}
-		
-		// Navigate beyond the stack, our own layout has been popped - close this tab
-		DTabs tabs = getWindowControl().getWindowBackOffice().getWindow().getDTabs();
-		if (tabs != null) {
-			DTab tab = tabs.getDTab(re.getOlatResource());
-			if (tab != null) {
-				tabs.removeDTab(ureq, tab);						
-			}
-		}
+		getWindowControl().getWindowBackOffice().getWindow().getDTabs()
+			.closeDTab(ureq, re.getOlatResource(), launchedFromPoint);
 	}
 	
 	protected void doEdit(UserRequest ureq) {
@@ -710,7 +686,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	protected Activateable2 doMembers(UserRequest ureq) {
 		if(!reSecurity.isEntryAdmin()) return null;
 
-		RepositoryMembersController ctrl = new RepositoryMembersController(ureq, getWindowControl(), re);
+		RepositoryMembersController ctrl = new RepositoryMembersController(ureq, getWindowControl(), toolbarPanel ,re);
 		listenTo(ctrl);
 		membersEditController = pushController(ureq, translate("details.members"), ctrl);
 		currentToolCtr = membersEditController;
diff --git a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
index 417ccba510d4ed6181e321347c75c90e7c865212..676f508bc70119e18dc462a6797eedac9e951285 100644
--- a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
+++ b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
@@ -22,9 +22,12 @@ package org.olat.repository.ui.author;
 import java.util.List;
 
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.link.Link;
-import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -44,6 +47,7 @@ import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.ui.main.AbstractMemberListController;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
+import org.olat.group.ui.main.MemberView;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
@@ -60,8 +64,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 public class RepositoryMembersController extends AbstractMemberListController {
 	
 	private final SearchMembersParams params;
-	private final RepositoryEntry repoEntry;
-	private Link importMemberLink, addMemberLink;
+	private FormLink importMemberLink, addMemberLink;
 	private StepsMainRunController importMembersWizard;
 	
 	@Autowired
@@ -69,21 +72,27 @@ public class RepositoryMembersController extends AbstractMemberListController {
 	@Autowired
 	private BusinessGroupService businessGroupService;
 
-	public RepositoryMembersController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry) {
-		super(ureq, wControl, repoEntry, null, "all_member_list",
-				Util.createPackageTranslator(RepositoryService.class, ureq.getLocale(), Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale())));
+	public RepositoryMembersController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RepositoryEntry repoEntry) {
+		super(ureq, wControl, repoEntry, null, "all_member_list", stackPanel,
+				Util.createPackageTranslator(RepositoryService.class, ureq.getLocale(),
+						Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale())));
+
+		params = new SearchMembersParams(true, true, true, true, true, true, true);
+		reloadModel();
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		super.initForm(formLayout, listener, ureq);
 		
-		this.repoEntry = repoEntry;
 		boolean managed = RepositoryEntryManagedFlag.isManaged(repoEntry, RepositoryEntryManagedFlag.membersmanagement);
-		addMemberLink = LinkFactory.createButton("add.member", mainVC, this);
+		addMemberLink = uifactory.addFormLink("add.member", formLayout, Link.BUTTON);
+		addMemberLink.setIconLeftCSS("o_icon o_icon-fw o_icon_add");
 		addMemberLink.setVisible(!managed);
-		mainVC.put("addMembers", addMemberLink);
-		importMemberLink = LinkFactory.createButton("import.member", mainVC, this);
-		importMemberLink.setVisible(!managed);
-		mainVC.put("importMembers", importMemberLink);
 
-		params = new SearchMembersParams(true, true, true, true, true, true, true);
-		reloadModel();
+		importMemberLink = uifactory.addFormLink("import.member", formLayout, Link.BUTTON);
+		importMemberLink.setIconLeftCSS("o_icon o_icon-fw o_icon_import");
+		importMemberLink.setVisible(!managed);
 	}
 
 	@Override
@@ -92,13 +101,13 @@ public class RepositoryMembersController extends AbstractMemberListController {
 	}
 	
 	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
-		 if (source == addMemberLink) {
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if (source == addMemberLink) {
 			doChooseMembers(ureq);
 		} else if (source == importMemberLink) {
 			doImportMembers(ureq);
 		} else {
-			super.event(ureq, source, event);
+			super.formInnerEvent(ureq, source, event);
 		}
 	}
 
@@ -118,6 +127,11 @@ public class RepositoryMembersController extends AbstractMemberListController {
 		}
 	}
 	
+	@Override
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+		//
+	}
+	
 	private void doChooseMembers(UserRequest ureq) {
 		removeAsListenerAndDispose(importMembersWizard);
 
diff --git a/src/main/java/org/olat/repository/ui/author/_content/all_member_list.html b/src/main/java/org/olat/repository/ui/author/_content/all_member_list.html
index 212414af16ed8b83c6ed8c17c00e65be061127f8..ea9ad56e5fa1d39dcb682aaa694b998e0dd62257 100644
--- a/src/main/java/org/olat/repository/ui/author/_content/all_member_list.html
+++ b/src/main/java/org/olat/repository/ui/author/_content/all_member_list.html
@@ -1,20 +1,27 @@
-#if($r.available("addMembers") || $r.available("importMembers"))
+#if($infos)
+	<div class="o_info">$infos</div>
+#end
+#if($r.available("add.member") || $r.available("import.member"))
 <div class="o_button_group o_button_group_right">
-	#if($r.available("addMembers"))
-		$r.render("addMembers")
+	#if($r.available("add.member") && $r.available("import.member"))<div class="btn-group">#end
+	#if($r.available("add.member"))
+		$r.render("add.member")
 	#end
-	#if($r.available("importMembers"))
-		$r.render("importMembers")
+	#if($r.available("import.member"))
+		$r.render("import.member")
 	#end
+	#if($r.available("add.member") && $r.available("import.member"))</div>#end
 </div>
 #end
-
-#if($infos)
-	<div class="o_block clearfix">
-		<p class="o_info">$infos</p>
-	</div>
-#end
-
-<div class="clearfix">
-	$r.render("memberList")
+$r.render("memberList")
+<div class="o_button_group">
+	#if($r.available("edit.members"))
+		$r.render("edit.members")
+	#end
+	#if($r.available("table.header.mail"))
+		$r.render("table.header.mail")
+	#end
+	#if($r.available("table.header.remove"))
+		$r.render("table.header.remove")
+	#end
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/OLATResourceImpl.hbm.xml b/src/main/java/org/olat/resource/OLATResourceImpl.hbm.xml
index ef7532c5535682550d68f43be4e8a0fb25e14a9e..8917f91f493986fc2ebfaa2640ea80c748ce9561 100644
--- a/src/main/java/org/olat/resource/OLATResourceImpl.hbm.xml
+++ b/src/main/java/org/olat/resource/OLATResourceImpl.hbm.xml
@@ -4,8 +4,6 @@
 	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
   <class name="org.olat.resource.OLATResourceImpl" table="o_olatresource">
-  		
-	<cache usage="transactional" />
 
 	<id name="key" type="long" column="resource_id"	unsaved-value="null">
 		<generator class="hilo"/>
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
index 9c6e5627d3d3665478df7957336065d25d4a2634..7824e9e7df60f9a55a8618832c075855f3cc4c5b 100644
--- a/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
@@ -57,7 +57,7 @@ public class ACReservationDAO {
 	
 	public ResourceReservation loadReservation(Identity identity, OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select reservation from ").append(ResourceReservationImpl.class.getName()).append(" as reservation ")
+		sb.append("select reservation from resourcereservation as reservation ")
 		  .append(" where reservation.resource.key=:resourceKey and reservation.identity.key=:identityKey");
 		
 		List<ResourceReservation> reservations = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), ResourceReservation.class)
@@ -70,7 +70,7 @@ public class ACReservationDAO {
 	
 	public List<ResourceReservation> loadReservations(List<OLATResource> resources) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select reservation from ").append(ResourceReservationImpl.class.getName()).append(" as reservation ")
+		sb.append("select reservation from resourcereservation as reservation ")
 		  .append(" where reservation.resource.key in (:resourceKey)");
 		
 		List<Long> resourceKeys = PersistenceHelper.toKeys(resources);
@@ -95,7 +95,7 @@ public class ACReservationDAO {
 	
 	public List<ResourceReservation> loadReservationOlderThan(Date date) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select reservation from ").append(ResourceReservationImpl.class.getName()).append(" as reservation ")
+		sb.append("select reservation from resourcereservation as reservation ")
 		  .append(" where reservation.creationDate<:date");
 		
 		List<ResourceReservation> reservations = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), ResourceReservation.class)
@@ -107,7 +107,7 @@ public class ACReservationDAO {
 	
 	public List<ResourceReservation> loadExpiredReservation(Date defaultDate) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select reservation from ").append(ResourceReservationImpl.class.getName()).append(" as reservation ")
+		sb.append("select reservation from resourcereservation as reservation ")
 		  .append(" where (reservation.expirationDate is null and reservation.creationDate<:date)")
 		  .append(" or (reservation.expirationDate<:nowDate)");
 		
@@ -121,7 +121,7 @@ public class ACReservationDAO {
 	
 	public int countReservations(OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(reservation) from ").append(ResourceReservationImpl.class.getName()).append(" as reservation ")
+		sb.append("select count(reservation) from resourcereservation as reservation ")
 		  .append(" where reservation.resource.key=:resourceKey");
 		
 		Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Reservation.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/Reservation.hbm.xml
deleted file mode 100644
index 68e4c5198b3ac9bfb758202eb805b6d76aef2cbb..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/resource/accesscontrol/model/Reservation.hbm.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-<hibernate-mapping default-lazy="false">
-	
-	<class name="org.olat.resource.accesscontrol.model.ResourceReservationImpl" table="o_ac_reservation">
-		<id name="key" column="reservation_id" type="long" unsaved-value="null">
-			<generator class="hilo"/>
-		</id>
-		
-		<version name="version" access="field" column="version" type="int"/>
-		<property name="creationDate" column="creationdate" type="timestamp" />
-		<property name="lastModified" column="lastmodified" type="timestamp" />
-		<property name="expirationDate" column="expirationdate" type="timestamp" />
-		
-		<property name="type" column="reservationtype" type="string" />
-		
-		<many-to-one name="identity"
-                 column="fk_identity"
-                 class="org.olat.basesecurity.IdentityImpl" 
-                 outer-join="true"   
-                 unique="false" 
-                 cascade="none"/>
-                 
-		<many-to-one name="resource"
-                 column="fk_resource"
-                 class="org.olat.resource.OLATResourceImpl" 
-                 outer-join="true"   
-                 unique="false" 
-                 cascade="none"/>
-                 
-	</class>
-	
-	
-	<query name="loadReservationsByIdentity">
-		<![CDATA[select reservation from org.olat.resource.accesscontrol.model.ResourceReservationImpl as reservation where reservation.identity.key=:identityKey]]>
-	</query>
-	
-</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/ResourceReservationImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/ResourceReservationImpl.java
index 67d5047afa872808a98f085cef820c5a2f6d3586..d74542c69660d7eeae5460ddef9535fe6ef1baf7 100644
--- a/src/main/java/org/olat/resource/accesscontrol/model/ResourceReservationImpl.java
+++ b/src/main/java/org/olat/resource/accesscontrol/model/ResourceReservationImpl.java
@@ -21,25 +21,87 @@ package org.olat.resource.accesscontrol.model;
 
 import java.util.Date;
 
-import org.olat.core.commons.persistence.PersistentObject;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Version;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.CreateInfo;
 import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
 import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceImpl;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class ResourceReservationImpl  extends PersistentObject implements ResourceReservation {
+@Entity(name="resourcereservation")
+@Table(name="o_ac_reservation")
+@NamedQueries({
+	@NamedQuery(name="loadReservationsByIdentity",query="select reservation from resourcereservation as reservation where reservation.identity.key=:identityKey")
+})
+public class ResourceReservationImpl implements CreateInfo, Persistable, ResourceReservation {
 
 	private static final long serialVersionUID = 2200260145344478778L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="reservation_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	@Version
+	private int version = 0;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
 	private Date lastModified;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="expirationdate", nullable=true, insertable=true, updatable=true)
 	private Date expirationDate;
-	
+	@Column(name="reservationtype", nullable=true, insertable=true, updatable=true)
+	private String type;
+
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY, optional=false)
+	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
 	private Identity identity;
+	@ManyToOne(targetEntity=OLATResourceImpl.class,fetch=FetchType.LAZY, optional=false)
+	@JoinColumn(name="fk_resource", nullable=false, insertable=true, updatable=false)
 	private OLATResource resource;
-	private String type;
-	
-	
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
 	@Override
 	public Date getLastModified() {
 		return lastModified;
@@ -103,4 +165,8 @@ public class ResourceReservationImpl  extends PersistentObject implements Resour
 		return false;
 	}
 
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
 }
diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
index 13654edc543726e99a641389aa4fafb7f74465b2..6e546dd560e9df98839fd044337ec1ee839e47dd 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
@@ -425,7 +425,7 @@ public class CoursesWebService {
 					description, copyResource, RepositoryEntry.ACC_OWNERS);
 		
 			RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(src);
-			preparedEntry = handler.copy(src, preparedEntry);
+			preparedEntry = handler.copy(ureq.getIdentity(), src, preparedEntry);
 			
 			preparedEntry.setCanDownload(src.getCanDownload());
 			if(StringHelper.containsNonWhitespace(softKey)) {
diff --git a/src/main/java/org/olat/upgrade/model/BGAreaUpgrade.hbm.xml b/src/main/java/org/olat/upgrade/model/BGAreaUpgrade.hbm.xml
index e6a133fbd243eb6fddcbe4f7023e2088f428565e..9bdf3401cf6fa2c57fd5e58719e4c219b6338ba5 100644
--- a/src/main/java/org/olat/upgrade/model/BGAreaUpgrade.hbm.xml
+++ b/src/main/java/org/olat/upgrade/model/BGAreaUpgrade.hbm.xml
@@ -5,8 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
     <class name="org.olat.upgrade.model.BGAreaUpgrade" table="o_gp_bgarea">
-    		
-		<cache usage="transactional" />
 
         <id name="key"
         	type="long"
diff --git a/src/main/java/org/olat/upgrade/model/BGResourceRelation.hbm.xml b/src/main/java/org/olat/upgrade/model/BGResourceRelation.hbm.xml
index 213a970586c365ce24f099174f9e3d59cf64dd96..2bbd7396c2f56c0025ce763701c32c09a1ea0822 100644
--- a/src/main/java/org/olat/upgrade/model/BGResourceRelation.hbm.xml
+++ b/src/main/java/org/olat/upgrade/model/BGResourceRelation.hbm.xml
@@ -5,8 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
 	<class name="org.olat.upgrade.model.BGResourceRelation" table="o_gp_business_to_resource">
-		<cache usage="transactional" />
-		
 		<id name="key" type="long" column="g_id" unsaved-value="null">
 			<generator class="hilo"/>
 		</id>
diff --git a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
index c70d328087f0559069522a448ca35f1f912923f7..89b896409df61a9f5e32cf3a651558780bb1fd22 100644
--- a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
+++ b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
@@ -5,8 +5,6 @@
 
 <hibernate-mapping default-lazy="false">
 	<class name="org.olat.upgrade.model.BusinessGroupUpgrade" table="o_gp_business">
-	
-		<cache usage="transactional" />
 		<!--
 		key (see Interface org.olat.core.commons.persistence.Persistable),
 		lastModified (see Interface org.olat.core.commons.persistence.Auditable)
diff --git a/src/main/java/org/olat/upgrade/model/RepositoryEntryUpgrade.hbm.xml b/src/main/java/org/olat/upgrade/model/RepositoryEntryUpgrade.hbm.xml
index ea0a510413e589068609077cd48b1a5bf1661223..a62d920640bf04744a38fc129fc21790da5d4fa6 100644
--- a/src/main/java/org/olat/upgrade/model/RepositoryEntryUpgrade.hbm.xml
+++ b/src/main/java/org/olat/upgrade/model/RepositoryEntryUpgrade.hbm.xml
@@ -2,8 +2,6 @@
 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping default-lazy="false">
 	<class name="org.olat.upgrade.model.RepositoryEntryUpgrade" table="o_repositoryentry">
-	
-		<cache usage="transactional" />
 
 		<id name="key" column="repositoryentry_id" type="long" unsaved-value="null">
 			<generator class="hilo"/>
diff --git a/src/main/java/org/olat/user/DisplayPortraitController.java b/src/main/java/org/olat/user/DisplayPortraitController.java
index a46c5b92b2c466b8c22a7f5b6cbafc90959e412f..75698deea60d742ca920b48d49fb6b6f3d023c7d 100644
--- a/src/main/java/org/olat/user/DisplayPortraitController.java
+++ b/src/main/java/org/olat/user/DisplayPortraitController.java
@@ -216,8 +216,9 @@ public class DisplayPortraitController extends BasicController implements Generi
 	 */
 	public void showUserInfo(UserRequest ureq) {
 		ControllerCreator ctrlCreator = new ControllerCreator() {
+			@Override
 			public Controller createController(UserRequest lureq, WindowControl lwControl) {
-				return new UserInfoMainController(lureq, lwControl, portraitIdent);
+				return new UserInfoMainController(lureq, lwControl, portraitIdent, true, false);
 			}					
 		};
 		//wrap the content controller into a full header layout
diff --git a/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java b/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
index 52e3cf97b8197fe3955987dcf19ee3fa99fdf9bc..cff2ce7041b88a12997640365fd89e2f2c55276b 100644
--- a/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
@@ -61,7 +61,7 @@ public class HomePageContextEntryControllerCreator extends DefaultContextEntryCo
 	public Controller createController(List<ContextEntry> ces, UserRequest ureq, WindowControl wControl) {
 		Identity identity = extractIdentity(ces.get(0));
 		if (identity == null) return null;
-		return new UserInfoMainController(ureq, wControl, identity);
+		return new UserInfoMainController(ureq, wControl, identity, false, true);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
index 494f90e7544e2b06ce4a24645ece0b0ca06bf96f..9cc213a054c05fe840cc9492000161b658617c0f 100644
--- a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
@@ -68,7 +68,7 @@ public class IdentityContextEntryControllerCreator extends DefaultContextEntryCo
 		if (id == null) {
 			return null;
 		}
-		return new UserInfoMainController(ureq, wControl, id);
+		return new UserInfoMainController(ureq, wControl, id, false, true);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/user/UserInfoMainController.java b/src/main/java/org/olat/user/UserInfoMainController.java
index af9f06977f24365b4240d5a5de358356fca20e0c..10f37c8e0e2fcc3a99146a00031a80b4eb78db71 100644
--- a/src/main/java/org/olat/user/UserInfoMainController.java
+++ b/src/main/java/org/olat/user/UserInfoMainController.java
@@ -45,6 +45,7 @@ import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.tree.GenericTreeModel;
 import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.gui.components.tree.MenuTree;
@@ -57,8 +58,10 @@ import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.HistoryPoint;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.UserSession;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
 import org.olat.core.util.resource.OresHelper;
@@ -94,6 +97,7 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 
 	private MenuTree menuTree;
 	private Panel main;
+	private TooledStackedPanel toolbarPanel;
 	
 	public static final OLATResourceable BUSINESS_CONTROL_TYPE_FOLDER = OresHelper.createOLATResourceableTypeWithoutCheck(FolderRunController.class
 			.getSimpleName());
@@ -106,6 +110,7 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 
 	private final Identity chosenIdentity;
 	private final String firstLastName;
+	private HistoryPoint launchedFromPoint;
 
 	@Autowired
 	private UserManager userManager;
@@ -117,10 +122,27 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 	 * @param wControl
 	 * @param chosenIdentity
 	 */
-	public UserInfoMainController(UserRequest ureq, WindowControl wControl, Identity chosenIdentity) {
+	public UserInfoMainController(UserRequest ureq, WindowControl wControl, Identity chosenIdentity,
+			boolean showRootNode, boolean showToolbar) {
 		super(ureq, wControl);
 				
 		this.chosenIdentity = chosenIdentity;
+		
+		UserSession session = ureq.getUserSession();
+		if(showToolbar && session != null &&  session.getHistoryStack() != null && session.getHistoryStack().size() >= 2) {
+			// Set previous business path as back link for this course - brings user back to place from which he launched the course
+			List<HistoryPoint> stack = session.getHistoryStack();
+			for(int i=stack.size() - 2; i-->0; ) {
+				HistoryPoint point = stack.get(stack.size() - 2);
+				if(point.getEntries().size() > 0) {
+					OLATResourceable ores = point.getEntries().get(0).getOLATResourceable();
+					if(!chosenIdentity.getKey().equals(ores.getResourceableId())) {
+						launchedFromPoint = point;
+						break;
+					}
+				}
+			}
+		}
 
 		main = new Panel("userinfomain");
 		Controller homeCtrl = createComponent(ureq, CMD_HOMEPAGE);
@@ -133,6 +155,7 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 		menuTree.setTreeModel(tm);
 		menuTree.setSelectedNodeId(tm.getRootNode().getChildAt(0).getIdent());
 		menuTree.addListener(this);
+		menuTree.setRootVisible(showRootNode);
 
 		// override if user is guest, don't show anything
 		if (ureq.getUserSession().getRoles().isGuestOnly()) {
@@ -142,7 +165,17 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 
 		LayoutMain3ColsController columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, main, "userinfomain");
 		listenTo(columnLayoutCtr);
-		putInitialPanel(columnLayoutCtr.getInitialComponent());
+		
+		if(showToolbar) {
+			toolbarPanel = new TooledStackedPanel("courseStackPanel", getTranslator(), this);
+			toolbarPanel.setInvisibleCrumb(0); // show root level
+			toolbarPanel.setToolbarEnabled(false);
+			toolbarPanel.setShowCloseLink(true, true);
+			toolbarPanel.pushController(firstLastName, columnLayoutCtr);
+			putInitialPanel(toolbarPanel);
+		} else {
+			putInitialPanel(columnLayoutCtr.getInitialComponent());
+		}
 	}
 	
 	@Override
@@ -161,6 +194,10 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 					main.setContent(controller.getInitialComponent());
 				}
 			}
+		} else if(source == toolbarPanel) {
+			if (event == Event.CLOSE_EVENT) {
+				doClose(ureq);
+			}
 		}
 	}
 
@@ -345,4 +382,9 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 		listenTo(portfolioController);
 		return portfolioController;
 	}
+	
+	protected final void doClose(UserRequest ureq) {
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance("HomeSite", chosenIdentity.getKey());
+		getWindowControl().getWindowBackOffice().getWindow().getDTabs().closeDTab(ureq, ores, launchedFromPoint);
+	}
 }
\ No newline at end of file
diff --git a/src/main/resources/infinispan-config.xml b/src/main/resources/infinispan-config.xml
index 04d5227a2cca839531c5a2cc1c1df35ab06098cb..a9ed508232c1245fa1ab9ed51a909909225f65e2 100644
--- a/src/main/resources/infinispan-config.xml
+++ b/src/main/resources/infinispan-config.xml
@@ -11,6 +11,36 @@
       <jmxStatistics enabled="true"/>
    </default>
    
+	<!-- Hibernate caches --> 
+	<namedCache name="local-query">
+      <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000" useLockStriping="false"/>
+      <eviction maxEntries="10000" strategy="LRU"/>
+      <expiration maxIdle="100000" wakeUpInterval="5000"/>
+      <transaction transactionMode="NON_TRANSACTIONAL" />
+   </namedCache>
+   
+	<namedCache name="timestamps">
+	  <!-- 
+      <clustering mode="replication">
+         <async/>
+      </clustering>
+      -->
+      <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000" useLockStriping="false"/>
+      <!--  Don't ever evict modification timestamps -->
+      <eviction strategy="NONE"/>
+      <expiration wakeUpInterval="0"/>
+      <!-- Explicitly non transactional -->
+      <transaction transactionMode="NON_TRANSACTIONAL"/>
+      <!-- State transfer forces all replication calls to be synchronous,
+           so for calls to remain async, use a cluster cache loader instead -->
+      <persistence passivation="false">
+         <!--
+         <cluster remoteCallTimeout="20000" />
+         -->
+      </persistence>
+	</namedCache>
+   
+	<!-- Our own caches -->
 	<namedCache name="MapperService@mapper">
 		<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000" useLockStriping="false"/>
 		<eviction maxEntries="1000" strategy="LRU"/>
diff --git a/src/main/resources/org/olat/ims/qti/questionimport/qti-import-metadata.xlsx b/src/main/resources/org/olat/ims/qti/questionimport/qti-import-metadata.xlsx
index 194de4fb7b8de9e53e14e05eed2996f55ab81a8a..bdf350c980b768b89fe99925f08b7bda9ab258f5 100644
Binary files a/src/main/resources/org/olat/ims/qti/questionimport/qti-import-metadata.xlsx and b/src/main/resources/org/olat/ims/qti/questionimport/qti-import-metadata.xlsx differ
diff --git a/src/main/webapp/static/themes/light/modules/_icons.scss b/src/main/webapp/static/themes/light/modules/_icons.scss
index f96e3c9470d59350bbbeb63940602bd4f4b69c50..d33e003fc1c8e59ebdb3e661b0319f98be7ccefd 100644
--- a/src/main/webapp/static/themes/light/modules/_icons.scss
+++ b/src/main/webapp/static/themes/light/modules/_icons.scss
@@ -97,6 +97,7 @@ $fa-css-prefix: "o_icon" !default;
 .o_icon_external_link:before { content: $fa-var-external-link } 
 .o_icon_failed:before { content: $fa-var-times-circle;}
 .o_icon_filter:before { content: $fa-var-filter;}
+.o_icon_graduate:before { content: $fa-var-graduation-cap; }
 .o_icon_group:before, .o_BusinessGroup_icon:before { content: $fa-var-users; }
 .o_icon_header:before { content: $fa-var-header;}
 .o_icon_help:before { content: $fa-var-question-circle; cursor: help;}
@@ -233,6 +234,7 @@ $fa-css-prefix: "o_icon" !default;
 .o_icon_upload:before { content: $fa-var-upload; }
 .o_icon_version:before { content: $fa-var-history;}
 .o_icon_video:before { content: $fa-var-film; }
+.o_icon_waiting:before { content: $fa-var-clock-o; }
 .o_icon_warn:before { content: $fa-var-exclamation-triangle; color: $brand-warning;}
 .o_icon_wizard:before { content: $fa-var-magic; }
 
diff --git a/src/main/webapp/static/themes/light/theme.css b/src/main/webapp/static/themes/light/theme.css
index 3147f24524f25b7b34c59883a2bf2b338d33e9df..3c19746542c6bc4f3d01527717fe0e42caa7cd87 100644
--- a/src/main/webapp/static/themes/light/theme.css
+++ b/src/main/webapp/static/themes/light/theme.css
@@ -58,7 +58,7 @@ fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%
 @media (max-width: 767px){.hidden-xs{display:none !important}}@media (min-width: 768px) and (max-width: 991px){.hidden-sm{display:none !important}}@media (min-width: 992px) and (max-width: 1199px){.hidden-md{display:none !important}}@media (min-width: 1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}
 .visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}
 .visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}
-@media print{.hidden-print{display:none !important}}body .modal{position:absolute;overflow:visible}body div.tooltip-inner{max-width:400px}body div.popover{max-width:450px}body .modal-body.alert{border-radius:0}body .progress{margin-bottom:0}.panel-body:nth-child(n+2){border-top:1px solid #ddd}.panel .panel-heading[data-toggle="collapse"]{cursor:pointer}#o_ajax_busy_backdrop{bottom:0;z-index:1020}.form-control-feedback{top:10px}.form-horizontal .has-feedback .form-control-feedback{top:10px}.btn.btn-primary.o_disabled{color:#fff !important}body .progress-bar[aria-valuenow="1"],body .progress-bar[aria-valuenow="2"]{min-width:1px}@-moz-document url-prefix(){fieldset{display:table-cell}}@font-face{font-family:'openolat';src:url("../light/fonts/openolat/openolat.eot?4yacgg");src:url("../light/fonts/openolat/openolat.eot?#iefix4yacgg") format("embedded-opentype"),url("../light/fonts/openolat/openolat.woff?4yacgg") format("woff"),url("../light/fonts/openolat/openolat.ttf?4yacgg") format("truetype"),url("../light/fonts/openolat/openolat.svg?4yacgg#openolat") format("svg");font-weight:normal;font-style:normal}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.o_icon.pull-left{margin-right:.3em}.o_icon.pull-right{margin-left:.3em}.o_icon-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .o_icon-rotate-90,:root .o_icon-rotate-180,:root .o_icon-rotate-270,:root .o_icon-flip-horizontal,:root .o_icon-flip-vertical{filter:none}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon_accessibility:before{content:"\f193"}.o_icon_actions:before{content:"\f085"}.o_icon_archive_tool:before{content:"\f019"}.o_icon_assessment_mode:before{content:"\f044"}.o_icon_assessment_tool:before{content:"\f091"}.o_icon_attempt_limit:before{content:"\f021"}.o_icon_accept:before{content:"\f00c";color:#5cb85c}.o_icon_add:before{content:"\f055"}.o_icon_add_search:before{content:"\f00e"}.o_icon_audio:before{content:"\f028"}.o_icon_back:before{content:"\f053"}.o_icon_back_history:before{content:"\f1da"}.o_icon_banned:before{content:"\f0c3";color:#d9534f}.o_icon_bold:before{content:"\f032"}.o_icon_booking:before{content:"\f07a"}.o_icon_bookmark:before{content:"\f02e";color:#bc2d0c}.o_icon_bookmark_add:before{content:"\f097"}.o_icon_bookmark_header:before{content:"\f02e"}.o_icon_browse:before{content:"\f00e"}.o_icon_browsercheck:before{content:"\f164"}.o_icon_busy:before{content:"\f110"}.o_icon_calendar:before{content:"\f073"}.o_icon_calendar_enabled:before{content:"\f05d"}.o_icon_calendar_disabled:before{content:"\f10c"}.o_icon_calendar:before{content:"\f073"}.o_icon_caret:before{content:"\f0d7"}.o_icon_caret_right:before{content:"\f0da"}.o_icon_catalog:before{content:"\f0e8"}.o_icon_catalog_sub:before{content:"\f07b"}.o_icon_certificate:before{content:"\f0a3"}.o_icon_chat:before{content:"\f0e5"}.o_icon_check:before{content:"\f00c"}.o_icon_check_off:before{content:"\f096"}.o_icon_check_on:before{content:"\f046"}.o_icon_checkbox:before{content:"\f096"}.o_icon_checkbox_checked:before{content:"\f14a"}.o_icon_cleanup:before{content:"\f0f9"}.o_icon_close:before{content:"\f00d"}.o_icon_close_resource:before{content:"\f011"}.o_icon_close_tab:before{content:"\f00d"}.o_icon_close_tool:before{content:"\f00d"}.o_icon_close_tree:before{content:"\f0d7"}.o_icon_close_togglebox:before,.o_togglebox_wrapper .o_opener.o_in i:before{content:"\f0d7"}.o_icon_code:before{content:"\f121"}.o_icon_color_picker:before{content:"\f043"}.o_icon_copy:before{content:"\f0c5"}.o_icon_courseareas:before{content:"\f1db"}.o_icon_coursedb:before{content:"\f1c0"}.o_icon_courseeditor:before{content:"\f044"}.o_icon_coursefolder:before{content:"\f114"}.o_icon_courserun:before{content:"\f1b2"}.o_icon_comments:before{content:"\f086"}.o_icon_comments_none:before{content:"\f0e5"}.o_icon_content_popup:before{content:"\f08e"}.o_icon_correct_answer:before{content:"\f00c";color:#5cb85c}.o_icon_customize:before{content:"\f013"}.o_icon_delete_item:before{content:"\f1f8"}.o_icon_delete:before{content:"\f056";color:#A87E7E}.o_icon_details:before{content:"\f0eb"}.o_icon_description:before{content:"\f05a"}.o_icon_dev:before{content:"\f188"}.o_icon_disabled:before{content:"\f10c"}.o_icon_download:before{content:"\f019"}.o_icon_edit:before{content:"\f044"}.o_icon_edit_file:before{content:"\f044"}.o_icon_edit_metadata:before{content:"\f013"}.o_icon_enabled:before{content:"\f111"}.o_icon_enlarge:before{content:"\f00e"}.o_icon_eportfolio_add:before{content:"\f12e"}.o_icon_eportfolio_link:before{content:"\f12e"}.o_icon_error:before{content:"\f06a";color:#d9534f}.o_icon_expenditure:before{content:"\f017"}.o_icon_export:before{content:"\f045"}.o_icon_external_link:before{content:"\f08e"}.o_icon_failed:before{content:"\f057"}.o_icon_filter:before{content:"\f0b0"}.o_icon_group:before,.o_BusinessGroup_icon:before{content:"\f0c0"}.o_icon_header:before{content:"\f1dc"}.o_icon_help:before{content:"\f059";cursor:help}.o_icon_home:before{content:"\f015"}.o_icon_impress:before{content:"\f05a"}.o_icon_important:before{content:"\f071";color:#f0ad4e}.o_icon_import:before{content:"\f093"}.o_icon_info:before{content:"\f05a";color:#5bc0de}.o_icon_info_msg:before{content:"\f06a";color:#d9534f}.o_icon_inline_editable:before{content:"\f044"}.o_icon_institution:before{content:"\f19c"}.o_icon_italic:before{content:"\f033"}.o_icon_landingpage:before{content:"\f140"}.o_icon_language:before{content:"\f0ac"}.o_icon_layout:before{content:"\f1c5"}.o_icon_link:before{content:"\f0c1"}.o_icon_link_extern:before{content:"\f08e"}.o_icon_list:before{content:"\f03a"}.o_icon_list_num :before{content:"\f0cb"}.o_icon_lifecycle:before{content:"\f073"}.o_icon_locked:before{content:"\f023"}.o_icon_login:before{content:"\f090"}.o_icon_logout:before{content:"\f08b"}.o_icon_mandatory:before{content:"\f069";color:#f0ad4e}.o_icon_managed:before{content:"\f079";color:#777}.o_icon_manual:before{content:"\f02d";cursor:help}.o_icon_mail:before{content:"\f003"}.o_icon_math:before{content:"\f198"}.o_icon_membersmanagement:before{content:"\f0c0"}.o_icon_menuhandel:before{content:"\f0c9"}.o_icon_message:before{content:"\f0e0"}.o_icon_mobile:before{content:"\f10b"}.o_icon_move:before{content:"\f047"}.o_icon_move_down:before{content:"\f103"}.o_icon_move_left:before{content:"\f100"}.o_icon_move_right:before{content:"\f101"}.o_icon_move_up:before{content:"\f102"}.o_icon_new:before{content:"\f069";color:#5cb85c}.o_icon_new_document:before{content:"\f15c"}.o_icon_new_folder:before{content:"\f07b"}.o_icon_news:before{content:"\f05a"}.o_icon_next:before{content:"\f138"}.o_icon_next_page:before{content:"\f101"}.o_icon_next_toolbar:before{content:"\f0da"}.o_icon_node_after:before{content:"\f175"}.o_icon_node_before:before{content:"\f176"}.o_icon_node_under:before{content:"\f112"}.o_icon_notes:before{content:"\f1e8"}.o_icon_notification:before{content:"\f09e"}.o_icon_open_tree:before{content:"\f0da"}.o_icon_open_togglebox:before,.o_togglebox_wrapper .o_opener i:before{content:"\f0da"}.o_icon_openolat:before,.o_icon_provider_olat:before{content:"\E600";font-family:openolat;font-size:10px}.o_icon_options:before{content:"\f205"}.o_icon_pageing:before{content:"\f141"}.o_icon_passed:before{content:"\f058"}.o_icon_password:before{content:"\f023"}.o_icon_pending:before{content:"\f110"}.o_icon_phone:before{content:"\f095"}.o_icon_post:before{content:"\f0e5"}.o_icon_preview:before{content:"\f06e"}.o_icon_previous:before{content:"\f137"}.o_icon_previous_page:before{content:"\f100"}.o_icon_previous_toolbar:before{content:"\f0d9"}.o_icon_print:before{content:"\f02f"}.o_icon_private:before{content:"\f02f"}.o_icon_provider_adfs:before{content:"\f17a"}.o_icon_provider_facebook:before{content:"\f09a"}.o_icon_provider_google:before{content:"\f0d5"}.o_icon_provider_guest:before{content:"\f1ae"}.o_icon_provider_ldap:before{content:"\f19c"}.o_icon_provider_linkedin:before{content:"\f0e1"}.o_icon_provider_oauth:before{content:"\f0c2"}.o_icon_provider_shibboleth:before{content:"\f19c"}.o_icon_provider_twitter:before{content:"\f099"}.o_icon_publish:before{content:"\f064"}.o_icon_qrcode:before{content:"\f029"}.o_icon_quickview:before{content:"\f06e"}.o_icon_radio_off:before{content:"\f10c"}.o_icon_radio_on:before{content:"\f05d"}.o_icon_rating_on:before,.o_rating .o_rating_items.o_enabled .o_icon:hover:before{content:"\f005"}.o_icon_rating_off:before{content:"\f006"}.o_icon_read:before{content:"\f10c"}.o_icon_readonly:before{content:"\f044";color:red}.o_icon_readwrite:before{content:"\f044"}.o_icon_recycle:before{content:"\f1b8"}.o_icon_refresh:before{content:"\f021"}.o_icon_reject:before{content:"\f00d";color:#d9534f}.o_icon_reminder:before{content:"\f0a6"}.o_icon_remove:before{content:"\f00d"}.o_icon_replace:before{content:"\f0c5"}.o_icon_reply:before{content:"\f112"}.o_icon_reply_with_quote:before{content:"\f122"}.o_icon_response_feedback:before{content:"\f021"}.o_icon_review:before{content:"\f06e"}.o_icon_rss:before{content:"\f09e"}.o_icon_rss_unsubscribe:before{content:"\f09e";color:#996633}.o_icon_search:before{content:"\f002"}.o_icon_select:before{content:"\f00c"}.o_icon_send:before{content:"\f0e0"}.o_icon_settings:before{content:"\f085"}.o_icon_share:before{content:"\f064"}.o_icon_show_more:before{content:"\f150"}.o_icon_show_less:before{content:"\f151"}.o_icon_show_send:before{content:"\f1d9"}.o_icon_sign_out:before{content:"\f08b"}.o_icon_spacer:before{content:"\f07e"}.o_icon_split:before{content:"\f127"}.o_icon_sort:before{content:"\f0dc"}.o_icon_sort_asc:before{content:"\f0de"}.o_icon_sort_desc:before{content:"\f0dd"}.o_icon_sort_menu:before{content:"\f160"}.o_icon_start:before{content:"\f054"}.o_icon_status_available:before{content:"\f111";color:#063}.o_icon_status_chat:before{content:"\f075"}.o_icon_status_dnd:before{content:"\f192";color:#cc3}.o_icon_status_unavailable:before{content:"\f05c";color:#963}.o_icon_statistics_tool:before{content:"\f080"}.o_icon_submit:before{content:"\f00c"}.o_icon_table:before{content:"\f0ce"}.o_icon_table_large:before{content:"\f009"}.o_icon_tags:before{content:"\f02c"}.o_icon_timelimit:before{content:"\f1e2"}.o_icon_toggle:before{content:"\f111"}.o_icon_to_read:before{content:"\f111"}.o_icon_tool:before{content:"\f013"}.o_icon_tools:before{content:"\f0ad"}.o_icon_top:before{content:"\f077"}.o_icon_translation_item:before{content:"\f1c9"}.o_icon_translation_package:before{content:"\f115"}.o_icon_user:before{content:"\f007"}.o_icon_user_vip:before{content:"\f19d"}.o_icon_user_anonymous:before{content:"\f128"}.o_icon_upload:before{content:"\f093"}.o_icon_version:before{content:"\f1da"}.o_icon_video:before{content:"\f008"}.o_icon_warn:before{content:"\f071";color:#f0ad4e}.o_icon_wizard:before{content:"\f0d0"}.o_CourseModule_icon:before,.o_course_icon:before{content:"\f1b2"}.o_EPStructuredMapTemplate_icon:before{content:"\f12e"}.o_FileResource-BLOG_icon:before{content:"\f0a1"}.o_FileResource-IMSCP_icon:before{content:"\f187"}.o_FileResource-PODCAST_icon:before{content:"\f03d"}.o_FileResource-SHAREDFOLDER:before{content:"\f08e"}.o_FileResource-SCORMCP_icon:before{content:"\f187"}.o_FileResource-SURVEY_icon:before{content:"\f11a"}.o_FileResource-TEST_icon:before{content:"\f044"}.o_FileResource-WIKI_icon:before{content:"\f0ac"}.o_FileResource-SHAREDFOLDER_icon:before{content:"\f115"}.o_FileResource-GLOSSARY_icon:before{content:"\f19d"}.o_FileResource-PDF_icon:before{content:"\f1c1"}.o_FileResource-XLS_icon:before{content:"\f1c3"}.o_FileResource-PPT_icon:before{content:"\f1c4"}.o_FileResource-DOC_icon:before{content:"\f1c2"}.o_FileResource-ANIM_icon:before{content:"\f1c8"}.o_FileResource-IMAGE_icon:before{content:"\f1c5"}.o_FileResource-SOUND_icon:before{content:"\f1c7"}.o_FileResource-MOVIE_icon:before{content:"\f1c8"}.o_FileResource-FILE_icon:before{content:"\f016"}.o_CourseModule_icon_closed:before{content:"\f05e"}.o_sp_icon:before{content:"\f0f6"}.o_st_icon:before{content:"\f1b3"}.o_tu_icon:before{content:"\f08e"}.o_bc_icon:before{content:"\f115"}.o_lti_icon:before{content:"\f08e"}.o_cp_icon:before{content:"\f187"}.o_cp_item:before{content:"\f0f6"}.o_scorm_icon:before{content:"\f187"}.o_en_icon:before{content:"\f090"}.o_fo_icon:before{content:"\f0e6"}.o_co_icon:before{content:"\f003"}.o_infomsg_icon:before{content:"\f05a"}.o_cal_icon:before{content:"\f073"}.o_wiki_icon:before{content:"\f0ac"}.o_podcast_icon:before{content:"\f03d"}.o_blog_icon:before{content:"\f0a1"}.o_ep_icon:before{content:"\f12e"}.o_iqtest_icon:before{content:"\f044"}.o_iqself_icon:before{content:"\f044"}.o_iqsurv_icon:before{content:"\f11a"}.o_ta_icon:before{content:"\f0ae"}.o_gta_icon:before{content:"\f0ae"}.o_ms_icon:before{content:"\f087"}.o_dialog_icon:before{content:"\f0c5"}.o_projectbroker_icon:before{content:"\f10c"}.o_ll_icon:before{content:"\f0c1"}.o_den_icon:before{content:"\f133"}.o_cmembers_icon:before{content:"\f0c0"}.o_cl_icon:before{content:"\f046"}.o_vc_icon:before{content:"\f108"}.o_vitero_icon:before{content:"\f108"}.o_openmeetings_icon:before{content:"\f108"}.o_portlet_infomsg_icon:before{content:"\f05a"}.o_portlet_quickstart_icon:before{content:"\f1d9"}.o_portlet_bookmark_icon:before{content:"\f02e"}.o_portlet_groups_icon:before{content:"\f0c0"}.o_portlet_notes_icon:before{content:"\f1e8"}.o_portlet_noti_icon:before{content:"\f09e"}.o_portlet_eff_icon:before{content:"\f0a3"}.o_portlet_repository_student_icon:before{content:"\f1b3"}.o_portlet_repository_teacher_icon:before{content:"\f19d"}.o_portlet_iframe_icon:before{content:"\f005"}.o_portlet_sysinfo_icon:before{content:"\f0e4"}.o_portlet_dyk_icon:before{content:"\f0eb"}.o_portlet_infomessages_icon:before{content:"\f0e5"}.o_portlet_cal_icon:before{content:"\f073"}.o_portlet_institutions_icon:before{content:"\f19c"}.o_portlet_links_icon:before{content:"\f0c1"}.o_portlet_shibboleth_icon:before{content:"\f090"}.o_icon_qpool:before{content:"\f19c"}.o_icon_pool_private:before{content:"\f096"}.o_icon_pool_public:before{content:"\f046"}.o_icon_pool_my_items:before{content:"\f007"}.o_icon_pool_favorits:before{content:"\f02e"}.o_icon_pool_collection:before{content:"\f03a"}.o_icon_pool_pool:before{content:"\f1e1"}.o_icon_pool_share:before{content:"\f0c0"}.o_forum_message_icon:before{content:"\f0e5"}.o_calendar_icon:before{content:"\f073"}.o_forum_status_thread_icon:before{content:"\f0e6"}.o_forum_status_sticky_closed_icon:before{content:"\f05e"}.o_forum_status_sticky_icon:before{content:"\f086"}.o_forum_status_closed_icon:before{content:"\f05e";color:#a94442}.o_forum_status_opened_icon:before{content:"\f05e";color:#3c763d}.o_forum_status_hidden_icon:before{content:"\f070";color:#a94442}.o_forum_status_visible_icon:before{content:"\f06e";color:#3c763d}.o_mi_qpool_import:before{content:"\f1c0"}.o_mi_qtisection:before{content:"\f1b3"}.o_mi_qtisc:before{content:"\f192"}.o_mi_qtimc:before{content:"\f046"}.o_mi_qtikprim:before{content:"\f14a"}.o_mi_qtifib:before{content:"\f141"}.o_mi_qtiessay:before{content:"\f036"}.o_as_mode_leadtime:before{content:"\f017"}.o_as_mode_assessment:before{content:"\f04b"}.o_as_mode_followup:before{content:"\f05e"}.o_as_mode_closed:before{content:'-'}.o_black_led:before{content:"\f111";color:#337ab7}.o_green_led:before{content:"\f111";color:#5cb85c}.o_yellow_led:before{content:"\f111";color:#f0ad4e}.o_red_led:before{content:"\f111";color:#d9534f}.o_ac_token_icon:before{content:"\f084"}.o_ac_free_icon:before{content:"\f06b"}.o_ac_group_icon:before{content:"\f0c0"}.o_ac_membersonly_icon:before{content:"\f023"}.o_ac_paypal_icon:before{content:"\f1f4"}.o_ac_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_status_new_icon:before{content:"\f069";color:#337ab7}.o_ac_status_succes_icon:before{content:"\f00c";color:#5cb85c}.o_ac_status_waiting_icon:before{content:"\f017";color:#337ab7}.o_ac_order_status_new_icon:before{content:"\f069";color:#337ab7}.o_ac_order_status_prepayment_icon:before{content:"\f0d6";color:#5bc0de}.o_ac_order_status_payed_icon:before{content:"\f00c";color:#5cb85c}.o_ac_order_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_order_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_order_status_warning_icon:before{content:"\f12a";color:#f0ad4e}.o_scorm_org:before{content:"\f187"}.o_scorm_item:before{content:"\f016"}.o_scorm_completed:before,.o_scorm_passed:before{content:"\f058"}.o_scorm_failed:before{content:"\f071"}.o_scorm_incomplete:before{content:"\f071"}.o_scorm_not_attempted:before{background:none}.o_midpub:before{content:"\f058"}.o_midwarn:before{content:"\f071"}.o_midlock:before{content:"\f023"}.o_miderr:before{content:"\f071"}.o_middel:before{content:"\f12d"}.o_filetype_file:before,.o_filetype_ico:before{content:"\f016"}.o_filetype_folder:before{content:"\f114"}.o_filetype_folder_open:before{content:"\f115"}.o_filetype_zip:before,.o_filetype_gz:before,.o_filetype_tar:before,.o_filetype_tgz:before{content:"\f1c6"}.o_filetype_css:before,.o_filetype_js:before,.o_filetype_java:before,.o_filetype_numbers:before,.o_filetype_ods:before,.o_filetype_xml:before,.o_filetype_xsl:before{content:"\f1c9"}.o_filetype_bat_icon:before,.o_filetype_bat:before,.o_filetype_exe:before,.o_filetype_app:before,.o_filetype_sh:before{content:"\f1c9"}.o_filetype_xls:before,.o_filetype_xlsx:before{content:"\f1c3"}.o_filetype_png:before,.o_filetype_tiff:before,.o_filetype_webp:before,.o_filetype_gif:before,.o_filetype_ico:before,.o_filetype_jpeg:before,.o_filetype_bmp:before,.o_filetype_odg:before,.o_filetype_eps:before,.o_filetype_jpg:before{content:"\f1c5"}.o_filetype_psd:before,.o_filetype_avi:before,.o_filetype_dvi:before,.o_filetype_mp4:before,.o_filetype_m4v:before,.o_filetype_webm:before,.o_filetype_ogg:before,.o_filetype_video:before,.o_filetype_mov:before,.o_filetype_mpeg:before,.o_filetype_mpg:before,.o_filetype_qt:before,.o_filetype_ra:before,.o_filetype_ram:before,.o_filetype_swf:before,.o_filetype_flv:before{content:"\f1c8"}.o_filetype_midi:before,.o_filetype_audio:before,.o_filetype_mp3:before,.o_filetype_m3u:before,.o_filetype_wav:before{content:"\f1c7"}.o_filetype_ps:before,.o_filetype_pdf:before{content:"\f1c1"}.o_filetype_key:before,.o_filetype_odp:before,.o_filetype_ppt:before,.o_filetype_pptx:before{content:"\f1c4"}.o_filetype_odf:before,.o_filetype_rtf:before,.o_filetype_readme:before,.o_filetype_README:before,.o_filetype_log:before,.o_filetype_txt:before,.o_filetype_htm:before,.o_filetype_html:before{content:"\f0f6"}.o_filetype_odt:before,.o_filetype_pages:before,.o_filetype_doc:before,.o_filetype_docx:before{content:"\f1c2"}.o_icon_share_social:before{content:"\f14d"}.o_icon_apple:before{content:"\f179"}.o_icon_facebook:before{content:"\f082"}.o_icon_twitter:before{content:"\f081"}.o_icon_google:before{content:"\f0d4"}.o_icon_delicious:before{content:"\f1a5"}.o_icon_digg:before{content:"\f1a6"}.o_icon_mailto:before{content:"\f199"}.o_icon_link:before{content:"\f0c1"}.o_icon_yahoo:before{content:"\f19e"}a.o_icon:hover,a.o_icon:focus{text-decoration:none}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}.o_block_bottom,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry,.o_header_with_buttons,.o_search_result{margin-bottom:1em}.o_block_top,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry{margin-top:1em}.o_block_large_bottom,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-bottom:2em}.o_block_large_top,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-top:2em}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_header_with_buttons h2{display:inline-block}.o_header_with_buttons .o_button_group{margin-top:10px;margin-bottom:0;float:right}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small,.o_comments .o_comment_wrapper h5,.o_comments .o_comment_wrapper .o_comment,.o_bc_meta,.tooltip,.o_htmleditor .o_metadata .o_lastmodified,.o_noti,.o_block_with_datecomp .o_meta,.o_togglebox_wrapper div.o_togglebox_content .o_hide,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label,.o_course_run .o_toc .o_entry{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,#o_main_wrapper #o_toplink:hover,#o_footer_powered a:hover,#o_share a:hover,#o_share_social_container a:hover,.o_toolbar .o_tools_container a:hover,.o_button_toggle:hover,.o_im_message_group .o_im_from:hover,.o_noti .o_label:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover,.o_catalog .o_level .o_meta .o_title a:hover,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover,.o_repo_details .o_social .o_comments:hover,.o_login .o_login_register:hover,.o_disabled:focus,.b_disabled:focus,#o_main_wrapper #o_toplink:focus,#o_footer_powered a:focus,#o_share a:focus,#o_share_social_container a:focus,.o_toolbar .o_tools_container a:focus,.o_button_toggle:focus,.o_im_message_group .o_im_from:focus,.o_noti .o_label:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:focus,.o_catalog .o_level .o_meta .o_title a:focus,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:focus,.o_repo_details .o_social .o_comments:focus,.o_login .o_login_register:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.b_video{display:inline-block;max-width:100%;height:auto}.o_image,img,.b_image{display:inline-block;max-width:100%;height:auto}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}h1{color:#337ab7}h2{color:#337ab7}h3{color:#337ab7}h4,.o_cal .fc-header-title h2{color:#337ab7}h5{color:#337ab7}h5{color:#337ab7}fieldset legend{color:#333}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid th{background:#eee}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border th{background:#eee}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#337ab7}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f08e"}a.b_link_mailto{color:#337ab7}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f003"}a.b_link_forward{color:#337ab7}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f064"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}span.olatFlashMovieViewer{max-width:100%;height:auto !important}.mejs-container,.mejs-mediaelement video,.mejs-layers div{max-width:100%}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:80px}#o_main_wrapper{background:#fff;z-index:3}#o_main_wrapper #o_main_container{background:#fff}#o_main_wrapper #o_main_container #o_main_left{float:left;z-index:2;position:relative;background:#fff}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:0 0 0 15px}#o_main_wrapper #o_main_container #o_main_left #o_main_left_toggle{position:absolute;display:none;right:0;top:70px;margin-right:-30px;font-size:25px;line-height:35px;text-align:center;width:30px;height:35px;z-index:3;border:1px solid #ddd;border-left:none;border-bottom-right-radius:4px;border-top-right-radius:4px;background-color:#fbfbfb;-webkit-box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);color:#337ab7}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas{background:#fbfbfb;-webkit-box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);min-width:250px}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas #o_main_left_content{padding:0 0 0 0}#o_main_wrapper #o_main_container #o_main_right{float:right;z-index:2;position:relative;background:inherit}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:0 15px 0 0}#o_main_wrapper #o_main_container #o_main_center{position:relative;z-index:1;background:inherit}#o_main_wrapper #o_main_container #o_main_center h2:first-child{margin-top:0}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:0 15px}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content #o_main_center_content_inner{padding-bottom:15px}#o_main_wrapper #o_toplink{position:absolute;bottom:0;right:15px;text-align:center;z-index:3}@media (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:15px}}
+@media print{.hidden-print{display:none !important}}body .modal{position:absolute;overflow:visible}body div.tooltip-inner{max-width:400px}body div.popover{max-width:450px}body .modal-body.alert{border-radius:0}body .progress{margin-bottom:0}.panel-body:nth-child(n+2){border-top:1px solid #ddd}.panel .panel-heading[data-toggle="collapse"]{cursor:pointer}#o_ajax_busy_backdrop{bottom:0;z-index:1020}.form-control-feedback{top:10px}.form-horizontal .has-feedback .form-control-feedback{top:10px}.btn.btn-primary.o_disabled{color:#fff !important}body .progress-bar[aria-valuenow="1"],body .progress-bar[aria-valuenow="2"]{min-width:1px}@-moz-document url-prefix(){fieldset{display:table-cell}}@font-face{font-family:'openolat';src:url("../light/fonts/openolat/openolat.eot?4yacgg");src:url("../light/fonts/openolat/openolat.eot?#iefix4yacgg") format("embedded-opentype"),url("../light/fonts/openolat/openolat.woff?4yacgg") format("woff"),url("../light/fonts/openolat/openolat.ttf?4yacgg") format("truetype"),url("../light/fonts/openolat/openolat.svg?4yacgg#openolat") format("svg");font-weight:normal;font-style:normal}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.o_icon.pull-left{margin-right:.3em}.o_icon.pull-right{margin-left:.3em}.o_icon-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .o_icon-rotate-90,:root .o_icon-rotate-180,:root .o_icon-rotate-270,:root .o_icon-flip-horizontal,:root .o_icon-flip-vertical{filter:none}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon_accessibility:before{content:"\f193"}.o_icon_actions:before{content:"\f085"}.o_icon_archive_tool:before{content:"\f019"}.o_icon_assessment_mode:before{content:"\f044"}.o_icon_assessment_tool:before{content:"\f091"}.o_icon_attempt_limit:before{content:"\f021"}.o_icon_accept:before{content:"\f00c";color:#5cb85c}.o_icon_add:before{content:"\f055"}.o_icon_add_search:before{content:"\f00e"}.o_icon_audio:before{content:"\f028"}.o_icon_back:before{content:"\f053"}.o_icon_back_history:before{content:"\f1da"}.o_icon_banned:before{content:"\f0c3";color:#d9534f}.o_icon_bold:before{content:"\f032"}.o_icon_booking:before{content:"\f07a"}.o_icon_bookmark:before{content:"\f02e";color:#bc2d0c}.o_icon_bookmark_add:before{content:"\f097"}.o_icon_bookmark_header:before{content:"\f02e"}.o_icon_browse:before{content:"\f00e"}.o_icon_browsercheck:before{content:"\f164"}.o_icon_busy:before{content:"\f110"}.o_icon_calendar:before{content:"\f073"}.o_icon_calendar_enabled:before{content:"\f05d"}.o_icon_calendar_disabled:before{content:"\f10c"}.o_icon_calendar:before{content:"\f073"}.o_icon_caret:before{content:"\f0d7"}.o_icon_caret_right:before{content:"\f0da"}.o_icon_catalog:before{content:"\f0e8"}.o_icon_catalog_sub:before{content:"\f07b"}.o_icon_certificate:before{content:"\f0a3"}.o_icon_chat:before{content:"\f0e5"}.o_icon_check:before{content:"\f00c"}.o_icon_check_off:before{content:"\f096"}.o_icon_check_on:before{content:"\f046"}.o_icon_checkbox:before{content:"\f096"}.o_icon_checkbox_checked:before{content:"\f14a"}.o_icon_cleanup:before{content:"\f0f9"}.o_icon_close:before{content:"\f00d"}.o_icon_close_resource:before{content:"\f011"}.o_icon_close_tab:before{content:"\f00d"}.o_icon_close_tool:before{content:"\f00d"}.o_icon_close_tree:before{content:"\f0d7"}.o_icon_close_togglebox:before,.o_togglebox_wrapper .o_opener.o_in i:before{content:"\f0d7"}.o_icon_code:before{content:"\f121"}.o_icon_color_picker:before{content:"\f043"}.o_icon_copy:before{content:"\f0c5"}.o_icon_courseareas:before{content:"\f1db"}.o_icon_coursedb:before{content:"\f1c0"}.o_icon_courseeditor:before{content:"\f044"}.o_icon_coursefolder:before{content:"\f114"}.o_icon_courserun:before{content:"\f1b2"}.o_icon_comments:before{content:"\f086"}.o_icon_comments_none:before{content:"\f0e5"}.o_icon_content_popup:before{content:"\f08e"}.o_icon_correct_answer:before{content:"\f00c";color:#5cb85c}.o_icon_customize:before{content:"\f013"}.o_icon_delete_item:before{content:"\f1f8"}.o_icon_delete:before{content:"\f056";color:#A87E7E}.o_icon_details:before{content:"\f0eb"}.o_icon_description:before{content:"\f05a"}.o_icon_dev:before{content:"\f188"}.o_icon_disabled:before{content:"\f10c"}.o_icon_download:before{content:"\f019"}.o_icon_edit:before{content:"\f044"}.o_icon_edit_file:before{content:"\f044"}.o_icon_edit_metadata:before{content:"\f013"}.o_icon_enabled:before{content:"\f111"}.o_icon_enlarge:before{content:"\f00e"}.o_icon_eportfolio_add:before{content:"\f12e"}.o_icon_eportfolio_link:before{content:"\f12e"}.o_icon_error:before{content:"\f06a";color:#d9534f}.o_icon_expenditure:before{content:"\f017"}.o_icon_export:before{content:"\f045"}.o_icon_external_link:before{content:"\f08e"}.o_icon_failed:before{content:"\f057"}.o_icon_filter:before{content:"\f0b0"}.o_icon_graduate:before{content:"\f19d"}.o_icon_group:before,.o_BusinessGroup_icon:before{content:"\f0c0"}.o_icon_header:before{content:"\f1dc"}.o_icon_help:before{content:"\f059";cursor:help}.o_icon_home:before{content:"\f015"}.o_icon_impress:before{content:"\f05a"}.o_icon_important:before{content:"\f071";color:#f0ad4e}.o_icon_import:before{content:"\f093"}.o_icon_info:before{content:"\f05a";color:#5bc0de}.o_icon_info_msg:before{content:"\f06a";color:#d9534f}.o_icon_inline_editable:before{content:"\f044"}.o_icon_institution:before{content:"\f19c"}.o_icon_italic:before{content:"\f033"}.o_icon_landingpage:before{content:"\f140"}.o_icon_language:before{content:"\f0ac"}.o_icon_layout:before{content:"\f1c5"}.o_icon_link:before{content:"\f0c1"}.o_icon_link_extern:before{content:"\f08e"}.o_icon_list:before{content:"\f03a"}.o_icon_list_num :before{content:"\f0cb"}.o_icon_lifecycle:before{content:"\f073"}.o_icon_locked:before{content:"\f023"}.o_icon_login:before{content:"\f090"}.o_icon_logout:before{content:"\f08b"}.o_icon_mandatory:before{content:"\f069";color:#f0ad4e}.o_icon_managed:before{content:"\f079";color:#777}.o_icon_manual:before{content:"\f02d";cursor:help}.o_icon_mail:before{content:"\f003"}.o_icon_math:before{content:"\f198"}.o_icon_membersmanagement:before{content:"\f0c0"}.o_icon_menuhandel:before{content:"\f0c9"}.o_icon_message:before{content:"\f0e0"}.o_icon_mobile:before{content:"\f10b"}.o_icon_move:before{content:"\f047"}.o_icon_move_down:before{content:"\f103"}.o_icon_move_left:before{content:"\f100"}.o_icon_move_right:before{content:"\f101"}.o_icon_move_up:before{content:"\f102"}.o_icon_new:before{content:"\f069";color:#5cb85c}.o_icon_new_document:before{content:"\f15c"}.o_icon_new_folder:before{content:"\f07b"}.o_icon_news:before{content:"\f05a"}.o_icon_next:before{content:"\f138"}.o_icon_next_page:before{content:"\f101"}.o_icon_next_toolbar:before{content:"\f0da"}.o_icon_node_after:before{content:"\f175"}.o_icon_node_before:before{content:"\f176"}.o_icon_node_under:before{content:"\f112"}.o_icon_notes:before{content:"\f1e8"}.o_icon_notification:before{content:"\f09e"}.o_icon_open_tree:before{content:"\f0da"}.o_icon_open_togglebox:before,.o_togglebox_wrapper .o_opener i:before{content:"\f0da"}.o_icon_openolat:before,.o_icon_provider_olat:before{content:"\E600";font-family:openolat;font-size:10px}.o_icon_options:before{content:"\f205"}.o_icon_pageing:before{content:"\f141"}.o_icon_passed:before{content:"\f058"}.o_icon_password:before{content:"\f023"}.o_icon_pending:before{content:"\f110"}.o_icon_phone:before{content:"\f095"}.o_icon_post:before{content:"\f0e5"}.o_icon_preview:before{content:"\f06e"}.o_icon_previous:before{content:"\f137"}.o_icon_previous_page:before{content:"\f100"}.o_icon_previous_toolbar:before{content:"\f0d9"}.o_icon_print:before{content:"\f02f"}.o_icon_private:before{content:"\f02f"}.o_icon_provider_adfs:before{content:"\f17a"}.o_icon_provider_facebook:before{content:"\f09a"}.o_icon_provider_google:before{content:"\f0d5"}.o_icon_provider_guest:before{content:"\f1ae"}.o_icon_provider_ldap:before{content:"\f19c"}.o_icon_provider_linkedin:before{content:"\f0e1"}.o_icon_provider_oauth:before{content:"\f0c2"}.o_icon_provider_shibboleth:before{content:"\f19c"}.o_icon_provider_twitter:before{content:"\f099"}.o_icon_publish:before{content:"\f064"}.o_icon_qrcode:before{content:"\f029"}.o_icon_quickview:before{content:"\f06e"}.o_icon_radio_off:before{content:"\f10c"}.o_icon_radio_on:before{content:"\f05d"}.o_icon_rating_on:before,.o_rating .o_rating_items.o_enabled .o_icon:hover:before{content:"\f005"}.o_icon_rating_off:before{content:"\f006"}.o_icon_read:before{content:"\f10c"}.o_icon_readonly:before{content:"\f044";color:red}.o_icon_readwrite:before{content:"\f044"}.o_icon_recycle:before{content:"\f1b8"}.o_icon_refresh:before{content:"\f021"}.o_icon_reject:before{content:"\f00d";color:#d9534f}.o_icon_reminder:before{content:"\f0a6"}.o_icon_remove:before{content:"\f00d"}.o_icon_replace:before{content:"\f0c5"}.o_icon_reply:before{content:"\f112"}.o_icon_reply_with_quote:before{content:"\f122"}.o_icon_response_feedback:before{content:"\f021"}.o_icon_review:before{content:"\f06e"}.o_icon_rss:before{content:"\f09e"}.o_icon_rss_unsubscribe:before{content:"\f09e";color:#996633}.o_icon_search:before{content:"\f002"}.o_icon_select:before{content:"\f00c"}.o_icon_send:before{content:"\f0e0"}.o_icon_settings:before{content:"\f085"}.o_icon_share:before{content:"\f064"}.o_icon_show_more:before{content:"\f150"}.o_icon_show_less:before{content:"\f151"}.o_icon_show_send:before{content:"\f1d9"}.o_icon_sign_out:before{content:"\f08b"}.o_icon_spacer:before{content:"\f07e"}.o_icon_split:before{content:"\f127"}.o_icon_sort:before{content:"\f0dc"}.o_icon_sort_asc:before{content:"\f0de"}.o_icon_sort_desc:before{content:"\f0dd"}.o_icon_sort_menu:before{content:"\f160"}.o_icon_start:before{content:"\f054"}.o_icon_status_available:before{content:"\f111";color:#063}.o_icon_status_chat:before{content:"\f075"}.o_icon_status_dnd:before{content:"\f192";color:#cc3}.o_icon_status_unavailable:before{content:"\f05c";color:#963}.o_icon_statistics_tool:before{content:"\f080"}.o_icon_submit:before{content:"\f00c"}.o_icon_table:before{content:"\f0ce"}.o_icon_table_large:before{content:"\f009"}.o_icon_tags:before{content:"\f02c"}.o_icon_timelimit:before{content:"\f1e2"}.o_icon_toggle:before{content:"\f111"}.o_icon_to_read:before{content:"\f111"}.o_icon_tool:before{content:"\f013"}.o_icon_tools:before{content:"\f0ad"}.o_icon_top:before{content:"\f077"}.o_icon_translation_item:before{content:"\f1c9"}.o_icon_translation_package:before{content:"\f115"}.o_icon_user:before{content:"\f007"}.o_icon_user_vip:before{content:"\f19d"}.o_icon_user_anonymous:before{content:"\f128"}.o_icon_upload:before{content:"\f093"}.o_icon_version:before{content:"\f1da"}.o_icon_video:before{content:"\f008"}.o_icon_waiting:before{content:"\f017"}.o_icon_warn:before{content:"\f071";color:#f0ad4e}.o_icon_wizard:before{content:"\f0d0"}.o_CourseModule_icon:before,.o_course_icon:before{content:"\f1b2"}.o_EPStructuredMapTemplate_icon:before{content:"\f12e"}.o_FileResource-BLOG_icon:before{content:"\f0a1"}.o_FileResource-IMSCP_icon:before{content:"\f187"}.o_FileResource-PODCAST_icon:before{content:"\f03d"}.o_FileResource-SHAREDFOLDER:before{content:"\f08e"}.o_FileResource-SCORMCP_icon:before{content:"\f187"}.o_FileResource-SURVEY_icon:before{content:"\f11a"}.o_FileResource-TEST_icon:before{content:"\f044"}.o_FileResource-WIKI_icon:before{content:"\f0ac"}.o_FileResource-SHAREDFOLDER_icon:before{content:"\f115"}.o_FileResource-GLOSSARY_icon:before{content:"\f19d"}.o_FileResource-PDF_icon:before{content:"\f1c1"}.o_FileResource-XLS_icon:before{content:"\f1c3"}.o_FileResource-PPT_icon:before{content:"\f1c4"}.o_FileResource-DOC_icon:before{content:"\f1c2"}.o_FileResource-ANIM_icon:before{content:"\f1c8"}.o_FileResource-IMAGE_icon:before{content:"\f1c5"}.o_FileResource-SOUND_icon:before{content:"\f1c7"}.o_FileResource-MOVIE_icon:before{content:"\f1c8"}.o_FileResource-FILE_icon:before{content:"\f016"}.o_CourseModule_icon_closed:before{content:"\f05e"}.o_sp_icon:before{content:"\f0f6"}.o_st_icon:before{content:"\f1b3"}.o_tu_icon:before{content:"\f08e"}.o_bc_icon:before{content:"\f115"}.o_lti_icon:before{content:"\f08e"}.o_cp_icon:before{content:"\f187"}.o_cp_item:before{content:"\f0f6"}.o_scorm_icon:before{content:"\f187"}.o_en_icon:before{content:"\f090"}.o_fo_icon:before{content:"\f0e6"}.o_co_icon:before{content:"\f003"}.o_infomsg_icon:before{content:"\f05a"}.o_cal_icon:before{content:"\f073"}.o_wiki_icon:before{content:"\f0ac"}.o_podcast_icon:before{content:"\f03d"}.o_blog_icon:before{content:"\f0a1"}.o_ep_icon:before{content:"\f12e"}.o_iqtest_icon:before{content:"\f044"}.o_iqself_icon:before{content:"\f044"}.o_iqsurv_icon:before{content:"\f11a"}.o_ta_icon:before{content:"\f0ae"}.o_gta_icon:before{content:"\f0ae"}.o_ms_icon:before{content:"\f087"}.o_dialog_icon:before{content:"\f0c5"}.o_projectbroker_icon:before{content:"\f10c"}.o_ll_icon:before{content:"\f0c1"}.o_den_icon:before{content:"\f133"}.o_cmembers_icon:before{content:"\f0c0"}.o_cl_icon:before{content:"\f046"}.o_vc_icon:before{content:"\f108"}.o_vitero_icon:before{content:"\f108"}.o_openmeetings_icon:before{content:"\f108"}.o_portlet_infomsg_icon:before{content:"\f05a"}.o_portlet_quickstart_icon:before{content:"\f1d9"}.o_portlet_bookmark_icon:before{content:"\f02e"}.o_portlet_groups_icon:before{content:"\f0c0"}.o_portlet_notes_icon:before{content:"\f1e8"}.o_portlet_noti_icon:before{content:"\f09e"}.o_portlet_eff_icon:before{content:"\f0a3"}.o_portlet_repository_student_icon:before{content:"\f1b3"}.o_portlet_repository_teacher_icon:before{content:"\f19d"}.o_portlet_iframe_icon:before{content:"\f005"}.o_portlet_sysinfo_icon:before{content:"\f0e4"}.o_portlet_dyk_icon:before{content:"\f0eb"}.o_portlet_infomessages_icon:before{content:"\f0e5"}.o_portlet_cal_icon:before{content:"\f073"}.o_portlet_institutions_icon:before{content:"\f19c"}.o_portlet_links_icon:before{content:"\f0c1"}.o_portlet_shibboleth_icon:before{content:"\f090"}.o_icon_qpool:before{content:"\f19c"}.o_icon_pool_private:before{content:"\f096"}.o_icon_pool_public:before{content:"\f046"}.o_icon_pool_my_items:before{content:"\f007"}.o_icon_pool_favorits:before{content:"\f02e"}.o_icon_pool_collection:before{content:"\f03a"}.o_icon_pool_pool:before{content:"\f1e1"}.o_icon_pool_share:before{content:"\f0c0"}.o_forum_message_icon:before{content:"\f0e5"}.o_calendar_icon:before{content:"\f073"}.o_forum_status_thread_icon:before{content:"\f0e6"}.o_forum_status_sticky_closed_icon:before{content:"\f05e"}.o_forum_status_sticky_icon:before{content:"\f086"}.o_forum_status_closed_icon:before{content:"\f05e";color:#a94442}.o_forum_status_opened_icon:before{content:"\f05e";color:#3c763d}.o_forum_status_hidden_icon:before{content:"\f070";color:#a94442}.o_forum_status_visible_icon:before{content:"\f06e";color:#3c763d}.o_mi_qpool_import:before{content:"\f1c0"}.o_mi_qtisection:before{content:"\f1b3"}.o_mi_qtisc:before{content:"\f192"}.o_mi_qtimc:before{content:"\f046"}.o_mi_qtikprim:before{content:"\f14a"}.o_mi_qtifib:before{content:"\f141"}.o_mi_qtiessay:before{content:"\f036"}.o_as_mode_leadtime:before{content:"\f017"}.o_as_mode_assessment:before{content:"\f04b"}.o_as_mode_followup:before{content:"\f05e"}.o_as_mode_closed:before{content:'-'}.o_black_led:before{content:"\f111";color:#337ab7}.o_green_led:before{content:"\f111";color:#5cb85c}.o_yellow_led:before{content:"\f111";color:#f0ad4e}.o_red_led:before{content:"\f111";color:#d9534f}.o_ac_token_icon:before{content:"\f084"}.o_ac_free_icon:before{content:"\f06b"}.o_ac_group_icon:before{content:"\f0c0"}.o_ac_membersonly_icon:before{content:"\f023"}.o_ac_paypal_icon:before{content:"\f1f4"}.o_ac_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_status_new_icon:before{content:"\f069";color:#337ab7}.o_ac_status_succes_icon:before{content:"\f00c";color:#5cb85c}.o_ac_status_waiting_icon:before{content:"\f017";color:#337ab7}.o_ac_order_status_new_icon:before{content:"\f069";color:#337ab7}.o_ac_order_status_prepayment_icon:before{content:"\f0d6";color:#5bc0de}.o_ac_order_status_payed_icon:before{content:"\f00c";color:#5cb85c}.o_ac_order_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_order_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_order_status_warning_icon:before{content:"\f12a";color:#f0ad4e}.o_scorm_org:before{content:"\f187"}.o_scorm_item:before{content:"\f016"}.o_scorm_completed:before,.o_scorm_passed:before{content:"\f058"}.o_scorm_failed:before{content:"\f071"}.o_scorm_incomplete:before{content:"\f071"}.o_scorm_not_attempted:before{background:none}.o_midpub:before{content:"\f058"}.o_midwarn:before{content:"\f071"}.o_midlock:before{content:"\f023"}.o_miderr:before{content:"\f071"}.o_middel:before{content:"\f12d"}.o_filetype_file:before,.o_filetype_ico:before{content:"\f016"}.o_filetype_folder:before{content:"\f114"}.o_filetype_folder_open:before{content:"\f115"}.o_filetype_zip:before,.o_filetype_gz:before,.o_filetype_tar:before,.o_filetype_tgz:before{content:"\f1c6"}.o_filetype_css:before,.o_filetype_js:before,.o_filetype_java:before,.o_filetype_numbers:before,.o_filetype_ods:before,.o_filetype_xml:before,.o_filetype_xsl:before{content:"\f1c9"}.o_filetype_bat_icon:before,.o_filetype_bat:before,.o_filetype_exe:before,.o_filetype_app:before,.o_filetype_sh:before{content:"\f1c9"}.o_filetype_xls:before,.o_filetype_xlsx:before{content:"\f1c3"}.o_filetype_png:before,.o_filetype_tiff:before,.o_filetype_webp:before,.o_filetype_gif:before,.o_filetype_ico:before,.o_filetype_jpeg:before,.o_filetype_bmp:before,.o_filetype_odg:before,.o_filetype_eps:before,.o_filetype_jpg:before{content:"\f1c5"}.o_filetype_psd:before,.o_filetype_avi:before,.o_filetype_dvi:before,.o_filetype_mp4:before,.o_filetype_m4v:before,.o_filetype_webm:before,.o_filetype_ogg:before,.o_filetype_video:before,.o_filetype_mov:before,.o_filetype_mpeg:before,.o_filetype_mpg:before,.o_filetype_qt:before,.o_filetype_ra:before,.o_filetype_ram:before,.o_filetype_swf:before,.o_filetype_flv:before{content:"\f1c8"}.o_filetype_midi:before,.o_filetype_audio:before,.o_filetype_mp3:before,.o_filetype_m3u:before,.o_filetype_wav:before{content:"\f1c7"}.o_filetype_ps:before,.o_filetype_pdf:before{content:"\f1c1"}.o_filetype_key:before,.o_filetype_odp:before,.o_filetype_ppt:before,.o_filetype_pptx:before{content:"\f1c4"}.o_filetype_odf:before,.o_filetype_rtf:before,.o_filetype_readme:before,.o_filetype_README:before,.o_filetype_log:before,.o_filetype_txt:before,.o_filetype_htm:before,.o_filetype_html:before{content:"\f0f6"}.o_filetype_odt:before,.o_filetype_pages:before,.o_filetype_doc:before,.o_filetype_docx:before{content:"\f1c2"}.o_icon_share_social:before{content:"\f14d"}.o_icon_apple:before{content:"\f179"}.o_icon_facebook:before{content:"\f082"}.o_icon_twitter:before{content:"\f081"}.o_icon_google:before{content:"\f0d4"}.o_icon_delicious:before{content:"\f1a5"}.o_icon_digg:before{content:"\f1a6"}.o_icon_mailto:before{content:"\f199"}.o_icon_link:before{content:"\f0c1"}.o_icon_yahoo:before{content:"\f19e"}a.o_icon:hover,a.o_icon:focus{text-decoration:none}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}.o_block_bottom,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry,.o_header_with_buttons,.o_search_result{margin-bottom:1em}.o_block_top,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry{margin-top:1em}.o_block_large_bottom,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-bottom:2em}.o_block_large_top,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-top:2em}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_header_with_buttons h2{display:inline-block}.o_header_with_buttons .o_button_group{margin-top:10px;margin-bottom:0;float:right}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small,.o_comments .o_comment_wrapper h5,.o_comments .o_comment_wrapper .o_comment,.o_bc_meta,.tooltip,.o_htmleditor .o_metadata .o_lastmodified,.o_noti,.o_block_with_datecomp .o_meta,.o_togglebox_wrapper div.o_togglebox_content .o_hide,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label,.o_course_run .o_toc .o_entry{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,#o_main_wrapper #o_toplink:hover,#o_footer_powered a:hover,#o_share a:hover,#o_share_social_container a:hover,.o_toolbar .o_tools_container a:hover,.o_button_toggle:hover,.o_im_message_group .o_im_from:hover,.o_noti .o_label:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover,.o_catalog .o_level .o_meta .o_title a:hover,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover,.o_repo_details .o_social .o_comments:hover,.o_login .o_login_register:hover,.o_disabled:focus,.b_disabled:focus,#o_main_wrapper #o_toplink:focus,#o_footer_powered a:focus,#o_share a:focus,#o_share_social_container a:focus,.o_toolbar .o_tools_container a:focus,.o_button_toggle:focus,.o_im_message_group .o_im_from:focus,.o_noti .o_label:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:focus,.o_catalog .o_level .o_meta .o_title a:focus,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:focus,.o_repo_details .o_social .o_comments:focus,.o_login .o_login_register:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.b_video{display:inline-block;max-width:100%;height:auto}.o_image,img,.b_image{display:inline-block;max-width:100%;height:auto}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}h1{color:#337ab7}h2{color:#337ab7}h3{color:#337ab7}h4,.o_cal .fc-header-title h2{color:#337ab7}h5{color:#337ab7}h5{color:#337ab7}fieldset legend{color:#333}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid th{background:#eee}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border th{background:#eee}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#337ab7}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f08e"}a.b_link_mailto{color:#337ab7}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f003"}a.b_link_forward{color:#337ab7}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"\f064"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}span.olatFlashMovieViewer{max-width:100%;height:auto !important}.mejs-container,.mejs-mediaelement video,.mejs-layers div{max-width:100%}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:80px}#o_main_wrapper{background:#fff;z-index:3}#o_main_wrapper #o_main_container{background:#fff}#o_main_wrapper #o_main_container #o_main_left{float:left;z-index:2;position:relative;background:#fff}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:0 0 0 15px}#o_main_wrapper #o_main_container #o_main_left #o_main_left_toggle{position:absolute;display:none;right:0;top:70px;margin-right:-30px;font-size:25px;line-height:35px;text-align:center;width:30px;height:35px;z-index:3;border:1px solid #ddd;border-left:none;border-bottom-right-radius:4px;border-top-right-radius:4px;background-color:#fbfbfb;-webkit-box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);color:#337ab7}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas{background:#fbfbfb;-webkit-box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);min-width:250px}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas #o_main_left_content{padding:0 0 0 0}#o_main_wrapper #o_main_container #o_main_right{float:right;z-index:2;position:relative;background:inherit}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:0 15px 0 0}#o_main_wrapper #o_main_container #o_main_center{position:relative;z-index:1;background:inherit}#o_main_wrapper #o_main_container #o_main_center h2:first-child{margin-top:0}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:0 15px}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content #o_main_center_content_inner{padding-bottom:15px}#o_main_wrapper #o_toplink{position:absolute;bottom:0;right:15px;text-align:center;z-index:3}@media (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:15px}}
 #o_back_wrapper,#o_preview_wrapper{margin-top:10px}#o_back_wrapper.o_toolbar .o_breadcrumb .breadcrumb,#o_preview_wrapper.o_toolbar .o_breadcrumb .breadcrumb{font-size:14px}#o_footer_wrapper{position:absolute;bottom:0;width:100%;height:70px;overflow:hidden;background-color:#f5f5f5;color:#999;line-height:16px;font-size:12px}#o_footer_wrapper a{color:#999}#o_footer_wrapper a:hover{color:#000}#o_footer_container{position:relative;padding-top:10px;min-height:70px;background:#f5f5f5;z-index:1}#o_footer_user{position:absolute;left:15px;top:10px;z-index:1}#o_footer_user #o_counter{white-space:nowrap}#o_footer_user #o_username{white-space:nowrap;margin-right:1em}#o_footer_version{position:absolute;right:15px;top:10px;text-align:right;z-index:1}@media (max-width: 767px){#o_footer_version{padding-top:10px;text-align:left}}
 #o_footer_powered{position:absolute;top:30px;right:15px;z-index:1}#o_footer_powered img{opacity:0.6;filter:alpha(opacity=60)}#o_footer_powered img:hover{opacity:1;filter:alpha(opacity=100)}#o_footer_impressum{position:absolute;top:10px;width:100%;text-align:center;z-index:-1}#o_footer_impressum i{display:none}#o_footer_textline{position:absolute;top:30px;width:100%;text-align:center;z-index:-1}#o_share{margin-top:10px}#o_share a{opacity:0.6;filter:alpha(opacity=60)}#o_share a:hover{opacity:1;filter:alpha(opacity=100)}#o_share a,#o_share_social_container a{color:#999;margin:0 0.25em 0 0}#o_share a:hover,#o_share_social_container a:hover{color:#000}@media (max-width: 767px){#o_counter,#o_footer_version,#o_share{display:none}#o_footer_impressum{top:30px;text-align:left}#o_footer_textline{top:50px;text-align:left}#o_footer_powered{top:10px}#o_footer_powered a:after{content:"\221E";font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:bold;font-size:14px}#o_footer_powered img{display:none}}#o_navbar_wrapper{z-index:4;border-top:1px solid #e7e7e7;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1)}#o_navbar_wrapper #o_navbar_container{position:relative}a.o_disabled.navbar-text{margin:0}.o_navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid #e7e7e7;background-color:#f8f8f8}.o_navbar:before,.o_navbar:after{content:" ";display:table}.o_navbar:after{clear:both}.o_navbar .o_navbar_tabs li{max-width:150px}.o_navbar .o_navbar_tabs li a{padding-right:30px}.o_navbar .o_navbar_tabs li a:first-child span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.o_navbar .o_navbar_tabs .o_icon-fw{position:absolute;top:15px;left:0.5em;padding-top:3px;width:1em;height:1em;display:none}.o_navbar .o_navbar_tabs .o_navbar_tab_close{position:absolute;top:15px;right:0.5em;padding:0;width:1em;height:1em}.o_navbar .o_navbar_tabs .o_navbar_tab_close i:before{color:#d9534f}.o_navbar .o_navbar_tabs .o_navbar_tab_close:hover i:before{color:#c9302c}.o_navbar .o_custom_navbar-brand{background-position:5px 0;background-repeat:no-repeat;height:50px;width:120px}.o_navbar #o_navbar_langchooser{color:#777;padding:7px 15px}.o_navbar #o_navbar_langchooser form span+div{display:inline}.o_navbar #o_navbar_tools_permanent #o_navbar_print a,.o_navbar #o_navbar_tools_permanent #o_navbar_impress a,.o_navbar #o_navbar_tools_permanent #o_navbar_help a{color:#777;padding-right:0}.o_navbar #o_navbar_tools_permanent #o_navbar_login a{color:#f0ad4e}.o_navbar .o_navbar_tools>#o_navbar_tools_permanent>li>a>span{display:none}@media (min-width: 768px){.o_navbar .o_navbar_tools li.o_portrait>a>span{display:inline}}.o_navbar #o_navbar_tools_personal .o_navbar_tool a,.o_navbar #o_navbar_tools_permanent .o_navbar_tool a{padding-right:5px}.o_navbar #o_navbar_tools_personal #o_navbar_my_menu a,.o_navbar #o_navbar_tools_permanent #o_navbar_my_menu a{padding-left:45px}.o_navbar #o_navbar_tools_personal #o_navbar_my_menu .dropdown-menu a,.o_navbar #o_navbar_tools_permanent #o_navbar_my_menu .dropdown-menu a{padding-left:15px}.o_navbar #o_navbar_tools_personal #o_navbar_my_menu .o_portrait,.o_navbar #o_navbar_tools_permanent #o_navbar_my_menu .o_portrait{position:absolute;left:7px;top:10px}.o_navbar #o_navbar_tools_personal .o_logout,.o_navbar #o_navbar_tools_permanent .o_logout{color:#d9534f}.o_navbar.o_navbar-offcanvas .o_navbar_tab_close{top:10px;right:10px}.o_navbar.o_navbar-offcanvas .o_navbar-right a{padding:3px 20px;color:#9d9d9d}.o_navbar.o_navbar-offcanvas .o_navbar-right a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-right a:focus{color:#fff;background-color:transparent}.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout{color:#d9534f}.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout:hover,.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout:focus{color:#c9302c}.o_navbar.o_navbar-offcanvas .o_navbar-right a .o_icon-lg{font-size:1.0em;vertical-align:baseline}.o_navbar.o_navbar-offcanvas .o_navbar-right .divider{height:1px;margin:9px 0;overflow:hidden;background-color:none}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-header{padding-left:15px}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-toggle{display:none}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-menu{box-shadow:none;position:relative;top:0;left:0;display:block;float:none;background-color:#222;color:#9d9d9d;font-size:14px;border:none}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-menu .divider{background:none}.o_navbar.o_navbar-offcanvas .o_navbar-nav a{color:#9d9d9d;text-shadow:none}.o_navbar.o_navbar-offcanvas .o_navbar-nav a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav a:focus{background-color:transparent;color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a:focus{background-color:#090909;color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .o_navbar-link{color:#9d9d9d}.o_navbar.o_navbar-offcanvas .o_navbar-nav .o_navbar-link:hover{color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a{color:#777}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}#o_navbar_impress a span,#o_navbar_search_opener a span{display:none}body.o_dmz #o_navbar_print a span,body.o_dmz #o_navbar_impress a span,body.o_dmz #o_navbar_help a span,body.o_dmz #o_navbar_search_opener a span{display:inline}.o_navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;-webkit-overflow-scrolling:touch}.o_navbar-collapse:before,.o_navbar-collapse:after{content:" ";display:table}.o_navbar-collapse:after{clear:both}.o_navbar-collapse.o_collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.o_navbar-offcanvas .o_navbar-collapse{width:auto;box-shadow:none;margin-top:10px;margin-right:-15px;margin-left:-15px}.o_navbar-brand{float:left;font-size:18px;line-height:20px;height:50px;color:#777}.o_navbar-brand:hover,.o_navbar-brand:focus{text-decoration:none;color:#5e5e5e;background-color:transparent}.o_navbar-toggle{position:relative;margin-right:15px;margin-left:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;border:1px solid #ddd;border-radius:4px;background-color:transparent;background-image:none}.o_navbar-toggle:hover,.o_navbar-toggle:focus{outline:none;background-color:#ddd}.o_navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px;background-color:#888}.o_navbar-toggle .icon-bar+.icon-bar{margin-top:4px}#o_navbar_left-toggle{float:left}#o_navbar_right-toggle{float:right}.o_navbar-link{color:#777}.o_navbar-link:hover{color:#333}.o_navbar-nav{margin:7.5px -15px}.o_navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px;color:#777}.o_navbar-nav>li>a:hover,.o_navbar-nav>li>a:focus{color:#333;background-color:transparent}.o_navbar-nav>.active>a,.o_navbar-nav>.active>a:hover,.o_navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.o_navbar-nav>.disabled>a,.o_navbar-nav>.disabled>a:hover,.o_navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.o_navbar-nav>.open>a,.o_navbar-nav>.open>a:hover,.o_navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}.o_collapse .o_navbar-nav{float:left;margin:0}.o_collapse .o_navbar-nav>li{float:left}.o_collapse .o_navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.o_collapse .o_navbar-nav.o_navbar-right:last-child{margin-right:-15px}.o_collapse.o_navbar-collapse .o_navbar-left{float:left !important}.o_collapse.o_navbar-collapse .o_navbar-right{float:right !important}.o_navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid #e7e7e7;border-bottom:1px solid #e7e7e7;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8px;margin-bottom:8px}@media (max-width: 767px){.o_navbar-form .form-group{margin-bottom:5px}}
 .o_collapse .o_navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.o_collapse .o_navbar-form.o_navbar-right:last-child{margin-right:-15px}.o_navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.o_navbar-fixed-bottom .o_navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.o_navbar-btn{margin-top:8px;margin-bottom:8px}.o_navbar-btn.btn-sm,.btn-group-sm>.o_navbar-btn.btn{margin-top:10px;margin-bottom:10px}.o_navbar-btn.btn-xs,.btn-group-xs>.o_navbar-btn.btn{margin-top:14px;margin-bottom:14px}.o_navbar-text{margin-top:15px;margin-bottom:15px;color:#777}.o_collapse .o_navbar-text{float:left;margin-left:15px;margin-right:15px}.o_collapse .o_navbar-text.o_navbar-right:last-child{margin-right:0}.o_dropdown_tab{position:relative}.o_dropdown_tab>a:first-child{padding-right:30px}.o_dropdown_tab>a:first-child .o_icon-fw{display:none;position:absolute;top:0;left:10px;padding-top:3px;line-height:20px}.o_dropdown_tab>a:first-child span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.o_dropdown_tab .o_navbar_tab_close{position:absolute;top:0px;right:10px;padding-left:0px;padding-right:0px;color:#d9534f;background-color:inherit}.o_dropdown_tab .o_navbar_tab_close:focus,.o_dropdown_tab .o_navbar_tab_close:hover{color:#c9302c;background-color:inherit}#o_navbar_more .dropdown-menu .divider:last-child{display:none}@media (min-width: 768px){#o_navbar_more .dropdown-menu{max-width:300px}}@media (max-width: 767px){#o_navbar_more>li{position:inherit}#o_navbar_more .dropdown-menu{left:0px;right:0px}#o_navbar_more .dropdown-menu a,#o_navbar_more .dropdown-menu i{line-height:30px}#o_navbar_more .dropdown-menu .o_navbar_tab_close{line-height:inherit}}.o_body_popup #o_topnav_printview{display:inline-block}.o_body_popup #o_topnav_close{float:right}.o_body_popup #o_topnav_close span{display:block}.o_body_popup #o_navbar_tools_permanent li>a{background-color:transparent}.o_toolbar{position:relative;margin-bottom:20px;margin-top:-10px;border:1px solid #e7e7e7}.o_toolbar:before,.o_toolbar:after{content:" ";display:table}.o_toolbar:after{clear:both}@media (min-width: 768px){.o_toolbar{border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}}.o_toolbar .o_breadcrumb:before,.o_toolbar .o_breadcrumb:after{content:" ";display:table}.o_toolbar .o_breadcrumb:after{clear:both}.o_toolbar .o_breadcrumb .breadcrumb{margin-bottom:0;padding:5px 9px;font-size:11px;line-height:15px;border-radius:0;background:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close{float:right;position:relative;margin:0 0 0 15px;vertical-align:middle}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a{line-height:15px;color:#d9534f}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a:hover{color:#b52b27}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a i{font-size:16px}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a span{display:none}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close:before{content:none}.o_toolbar .o_tools_container{text-align:center;min-height:37px;position:realtive;background-color:#f8f8f8;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:1px solid #e7e7e7}.o_toolbar .o_tools_container:before,.o_toolbar .o_tools_container:after{content:" ";display:table}.o_toolbar .o_tools_container:after{clear:both}@media (max-width: 991px){.o_toolbar .o_tools_container{min-height:35px}}@media (max-width: 767px){.o_toolbar .o_tools_container{min-height:22px;text-align:left}}.o_toolbar .o_tools_container a{color:#777;display:inline-block}.o_toolbar .o_tools_container a:hover{color:#333}.o_toolbar .o_tools_container a.o_disabled{color:#aaa !important}.o_toolbar .o_tools_container a.o_disabled:hover{color:#aaa !important}.o_toolbar .o_tools_container a.active{color:#337ab7;background-color:transparent}.o_toolbar .o_tools_container .dropdown-menu a{display:block}.o_toolbar .o_tools_container .dropdown-menu a.active{color:#337ab7;background-color:transparent}.o_toolbar .o_tools{margin-top:8px;margin-bottom:5px}.o_toolbar .o_tool,.o_toolbar .o_text{position:relative;margin:0 10px}.o_toolbar .o_tool:first-child,.o_toolbar .o_text:first-child{margin-left:0}.o_toolbar .o_tool:last-child,.o_toolbar .o_text:last-child{margin-right:0}.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:18px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{display:block;font-size:12px}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{position:absolute;right:50%;top:-18px;margin-right:-12px;font-size:13px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:16px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{font-size:11px}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{top:-16.5px;margin-right:-11px;font-size:12px}}@media (max-width: 767px){.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:20px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{display:none}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{display:block;position:relative;top:0;left:0;margin-right:0}}.o_toolbar .o_tool .o_chelp,.o_toolbar .o_text .o_chelp{position:relative;top:-1em;vertical-align:top}.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{padding:0;margin-top:5px;border:1px solid #ccc;background-color:#eee}.o_toolbar .o_tool_next a,.o_toolbar .o_tool_previous a{color:#777}.o_toolbar .o_tool_next a:hover,.o_toolbar .o_tool_previous a:hover{color:#333}.o_toolbar .o_tool_next a.o_disabled,.o_toolbar .o_tool_previous a.o_disabled{color:#aaa !important}.o_toolbar .o_tool_next a.o_disabled:hover,.o_toolbar .o_tool_previous a.o_disabled:hover{color:#aaa !important}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:21px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{margin-top:4px}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:18px}}@media (max-width: 767px){.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{margin-top:0}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:20px}}.o_toolbar .o_tool_previous{margin-left:10px;border-bottom-left-radius:4px;border-top-left-radius:4px;border-right:0}.o_toolbar .o_tool_next{border-bottom-right-radius:4px;border-top-right-radius:4px}.o_toolbar .o_tool_dropdown{margin:0 10px}.o_toolbar .o_tool_dropdown:first-child{margin-left:0}.o_toolbar .o_tool_dropdown:last-child{margin-right:0}.o_toolbar .o_tool_dropdown a.dropdown-toggle{position:relative}.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:18px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span{display:block;font-size:12px}.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{position:absolute;right:50%;top:4px;margin-right:-20px;font-size:14px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:16px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span,.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{font-size:11px}.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{top:4px;margin-right:-18px;font-size:12px}}@media (max-width: 767px){.o_toolbar .o_tool_dropdown a.dropdown-toggle{padding:0 10px 0 5px}.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:20px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span{display:none}}.o_toolbar .o_tool_dropdown .dropdown-menu{text-align:left}.o_toolbar .o_tools_left{float:left}.o_toolbar .o_tools_right{float:right}.o_toolbar .o_tools_right_edge{float:right}@media (max-width: 991px){.o_toolbar .o_tools{margin-top:6px;margin-bottom:4px}.o_toolbar .o_tool span{max-width:10em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_toolbar .o_tool,.o_toolbar .o_text,.o_toolbar .o_tool_dropdown{margin:0 5px}}@media (max-width: 767px){.o_toolbar .o_tools{margin-top:6px;margin-bottom:4px}.o_toolbar .o_tools .o_chelp{top:0;vertical-align:top}.o_toolbar .o_tools_center{float:left}.o_toolbar .o_tool,.o_toolbar .o_text,.o_toolbar .o_tool_dropdown{margin:0 0;position:static}.o_toolbar .o_tool_dropdown .dropdown-menu{left:0px;right:0px}.o_toolbar .o_tool_dropdown .dropdown-menu a,.o_toolbar .o_tool_dropdown .dropdown-menu i{line-height:30px}.o_toolbar .o_tool_dropdown .dropdown-menu .o_navbar_tab_close{line-height:inherit}}
diff --git a/src/main/webapp/static/themes/light/theme_ie_completions.css b/src/main/webapp/static/themes/light/theme_ie_completions.css
index 04f78d41228619f452f264ac310b6745b6bebbee..7711310eaad5eb8319504b8a7ef72aabd9e23b38 100644
--- a/src/main/webapp/static/themes/light/theme_ie_completions.css
+++ b/src/main/webapp/static/themes/light/theme_ie_completions.css
@@ -1,4 +1,4 @@
-.o_cal_toptoolbar{margin-bottom:6px}.o_cal_toptoolbar .o_cal_toptoolbar_sub,.o_cal_toptoolbar .o_cal_toptoolbar_help{float:left;margin-right:12px}.o_feed .o_date,.o_feed .o_author{color:#777}.o_feed .o_subscription a{margin-right:1.5em}.o_feed .o_subscription .form-group{margin-bottom:5px}.o_feed .o_subscription .form-control{border:0;background:none;padding:0;height:auto;-webkit-box-shadow:none;box-shadow:none}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper{float:left}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_title,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_explanation,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_legend{display:none}.o_feed .o_blog_posts .o_ratings_and_comments a.o_comments span{display:none}.o_feed .o_content:before,.o_feed .o_content:after{content:" ";display:table}.o_feed .o_content:after{clear:both}.o_glossary .o_register{text-align:center}.o_glossary .o_meta{font-size:90%;color:#777;font-style:italic}.o_glossary dl dt:first-letter{font-size:21px}.o_glossary dl dt small{color:#777}.o_tm_glossary{border-bottom:1px dotted #666699 !important}.o_tm_yellow{background-color:#FFFF66}.o_tm_blue{background-color:#33FFFF}.o_tm_red{background-color:#FF3333}.o_tm_green{background-color:#99FF00}.o_reminder_rule{padding:5px 0}.o_segments_content{margin-top:20px}.o_tabbed_pane .o_tabbed_pane_content{padding:20px 0 6px 0}.o_togglebox_wrapper .o_opener{position:relative;left:-0.5em}.o_togglebox_wrapper div.o_togglebox_content{position:relative;margin:0}.o_togglebox_wrapper div.o_togglebox_content .o_hide{position:absolute;bottom:0.5em;right:1em}.o_toolboxes ul{margin:0 0 1.5em 0;padding:0 0 0 1.5em}.o_qrcode{width:256px;height:256px}#o_ajax_busy{position:absolute;left:50%;top:20em;margin-left:-2.5em;height:5em;width:5em;color:#fff;z-index:1201;display:none}#o_body.o_ajax_busy{cursor:busy}.o_exception .o_visual{position:relative;background-image:url("../light/images/lion-500x333.jpg");filter:grayscale(50%);-webkit-filter:grayscale(50%);-moz-filter:grayscale(50%);-ms-filter:grayscale(50%);-o-filter:grayscale(50%);width:500px;height:333px;background-repeat:no-repeat;background-position:50% 50%;background-size:contain;margin:0 0 10px 16px}@media (min-width: 768px) and (max-width: 991px){.o_exception .o_visual{width:375px;height:249px}}@media (min-width: 500px) and (max-width: 767px){.o_exception .o_visual{width:250px;height:166px}}@media (max-width: 500px){.o_exception .o_visual{background-size:cover}}.o_exception .jumbotron h1,.o_exception .o_repo_details .o_lead h1,.o_repo_details .o_exception .o_lead h1{color:#d9534f}.tt-input{width:400px}.tt-dropdown-menu{width:400px;margin-top:6px;padding:0 0 0;color:#555;background-color:#fff;border:1px solid #66afe9;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;-webkit-box-shadow:0 0 8px rgba(102,175,233,0.6);box-shadow:0 0 8px rgba(102,175,233,0.6)}.tt-suggestion{padding:6px 12px;font-size:14px;line-height:1.42857}.tt-suggestion.tt-cursor{color:#fff;background-color:#337ab7}.tt-suggestion p{margin:0}.o_search_link_extended,.o_search_link_simple{margin-top:12px;display:inline-block}.o_search_results_stats{color:#777;padding-left:1.5em}.o_search_highlight{margin-left:12px;font-size:12px}.o_search_result_title h4,.o_search_result_title .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_search_result_title h2{display:inline-block;margin-right:12px;margin-bottom:6px}.o_search_result_highlight{font-weight:bold}.o_search_result_context{color:#3c763d}.o_search_result_excerpt{color:#555}.o_search_result_details .o_togglebox_wrapper.o_block{margin-top:0;margin-bottom:0}.o_search_result_details .o_togglebox_wrapper .o_togglebox_content{color:#777;font-size:12px;background:#fff;padding:6px 12px}@media (max-width: 767px){.o_search_result_details{display:none}}
+ul.o_certificates li{padding:5px 0}ul.o_certificates li a.o_sel_certificate_delete{padding-left:2em}.o_cal_toptoolbar{margin-bottom:6px}.o_cal_toptoolbar .o_cal_toptoolbar_sub,.o_cal_toptoolbar .o_cal_toptoolbar_help{float:left;margin-right:12px}.o_feed .o_date,.o_feed .o_author{color:#777}.o_feed .o_subscription a{margin-right:1.5em}.o_feed .o_subscription .form-group{margin-bottom:5px}.o_feed .o_subscription .form-control{border:0;background:none;padding:0;height:auto;-webkit-box-shadow:none;box-shadow:none}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper{float:left}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_title,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_explanation,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_legend{display:none}.o_feed .o_blog_posts .o_ratings_and_comments a.o_comments span{display:none}.o_feed .o_content:before,.o_feed .o_content:after{content:" ";display:table}.o_feed .o_content:after{clear:both}.o_glossary .o_register{text-align:center}.o_glossary .o_meta{font-size:90%;color:#777;font-style:italic}.o_glossary dl dt:first-letter{font-size:21px}.o_glossary dl dt small{color:#777}.o_tm_glossary{border-bottom:1px dotted #666699 !important}.o_tm_yellow{background-color:#FFFF66}.o_tm_blue{background-color:#33FFFF}.o_tm_red{background-color:#FF3333}.o_tm_green{background-color:#99FF00}.o_reminder_rule{padding:5px 0}.o_segments_content{margin-top:20px}.o_tabbed_pane .o_tabbed_pane_content{padding:20px 0 6px 0}.o_togglebox_wrapper .o_opener{position:relative;left:-0.5em}.o_togglebox_wrapper div.o_togglebox_content{position:relative;margin:0}.o_togglebox_wrapper div.o_togglebox_content .o_hide{position:absolute;bottom:0.5em;right:1em}.o_toolboxes ul{margin:0 0 1.5em 0;padding:0 0 0 1.5em}.o_qrcode{width:256px;height:256px}#o_ajax_busy{position:absolute;left:50%;top:20em;margin-left:-2.5em;height:5em;width:5em;color:#fff;z-index:1201;display:none}#o_body.o_ajax_busy{cursor:busy}.o_exception .o_visual{position:relative;background-image:url("../light/images/lion-500x333.jpg");filter:grayscale(50%);-webkit-filter:grayscale(50%);-moz-filter:grayscale(50%);-ms-filter:grayscale(50%);-o-filter:grayscale(50%);width:500px;height:333px;background-repeat:no-repeat;background-position:50% 50%;background-size:contain;margin:0 0 10px 16px}@media (min-width: 768px) and (max-width: 991px){.o_exception .o_visual{width:375px;height:249px}}@media (min-width: 500px) and (max-width: 767px){.o_exception .o_visual{width:250px;height:166px}}@media (max-width: 500px){.o_exception .o_visual{background-size:cover}}.o_exception .jumbotron h1,.o_exception .o_repo_details .o_lead h1,.o_repo_details .o_exception .o_lead h1{color:#d9534f}.tt-input{width:400px}.tt-dropdown-menu{width:400px;margin-top:6px;padding:0 0 0;color:#555;background-color:#fff;border:1px solid #66afe9;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;-webkit-box-shadow:0 0 8px rgba(102,175,233,0.6);box-shadow:0 0 8px rgba(102,175,233,0.6)}.tt-suggestion{padding:6px 12px;font-size:14px;line-height:1.42857}.tt-suggestion.tt-cursor{color:#fff;background-color:#337ab7}.tt-suggestion p{margin:0}.o_search_link_extended,.o_search_link_simple{margin-top:12px;display:inline-block}.o_search_results_stats{color:#777;padding-left:1.5em}.o_search_highlight{margin-left:12px;font-size:12px}.o_search_result_title h4,.o_search_result_title .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_search_result_title h2{display:inline-block;margin-right:12px;margin-bottom:6px}.o_search_result_highlight{font-weight:bold}.o_search_result_context{color:#3c763d}.o_search_result_excerpt{color:#555}.o_search_result_details .o_togglebox_wrapper.o_block{margin-top:0;margin-bottom:0}.o_search_result_details .o_togglebox_wrapper .o_togglebox_content{color:#777;font-size:12px;background:#fff;padding:6px 12px}@media (max-width: 767px){.o_search_result_details{display:none}}
 .wizard{border:1px solid #d4d4d4;border-radius:2px;background-color:#f9f9f9;position:relative;overflow:hidden;margin-bottom:15px}.wizard ul{list-style:none outside none;padding:0;margin:0;width:4000px}.wizard ul li{float:left;margin:0;padding:0 20px 0 30px;height:46px;line-height:46px;position:relative;background:#ededed;color:#333;font-size:16px;cursor:default}.wizard ul li .chevron{border:24px solid transparent;border-left:14px solid #d4d4d4;border-right:0;display:block;position:absolute;right:-14px;top:0;z-index:1}.wizard ul li .chevron:before{border:24px solid transparent;border-left:14px solid #ededed;border-right:0;content:"";display:block;position:absolute;right:1px;top:-24px}.wizard ul li.active{background:#f1f6fc;color:#333}.wizard ul li.active .chevron:before{border-left:14px solid #f1f6fc}.wizard ul li .badge{margin-right:8px}.wizard ul li:first-child{border-radius:4px 0 0 4px;padding-left:20px}.o_process{position:relative;padding-left:25px}.o_process .o_step{position:relative;height:auto;padding-top:10px;padding-left:30px;padding-bottom:10px}.o_process .o_bar{position:absolute;top:10px;left:8px;height:100%;border-left:4px solid #777}.o_process .o_bar:after{position:absolute;top:0;left:-10px;height:16px;width:16px;border:4px solid #777;border-radius:16px;background:#fff;content:" "}.o_process .o_title{margin-top:-1px;color:#777 !important}.o_process .o_step.o_active .o_bar,.o_process .o_step.o_active .o_bar:after{border-color:#337ab7}.o_process .o_step.o_active .o_title{color:#337ab7 !important}.o_process .o_step.o_active .o_title:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f0a4"}.o_process .o_step.o_done .o_bar,.o_process .o_step.o_done .o_bar:after{border-color:#5094ce}.o_process .o_step.o_done .o_title{color:#5094ce !important}.o_process .o_step.o_done .o_title:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f00c"}.o_process .o_meta{color:#777;font-size:12px;margin-top:-0.5em}.o_cal_orange{background:#ffc266;border-color:#ff9900;color:#5D5D5D}.o_cal_orange .o_cal_wv_event_header{background:#ff9900}.o_cal_orange a{color:#5d5d5d !important}.o_cal_green{background:#66c266;border-color:#009900;color:#FFF}.o_cal_green .o_cal_wv_event_header{background:#009900}.o_cal_green a{color:#fff !important}.o_cal_blue{background:#4d6e9f;border-color:#2e5894;color:#FFF}.o_cal_blue .o_cal_wv_event_header{background:#2e5894}.o_cal_blue a{color:#fff !important}.o_cal_yellow{background:#ffe066;border-color:#ffcc00;color:#5D5D5D}.o_cal_yellow .o_cal_wv_event_header{background:#ffcc00}.o_cal_yellow a{color:#5d5d5d !important}.o_cal_red{background:#c26666;border-color:#990000;color:#FFF}.o_cal_red .o_cal_wv_event_header{background:#990000}.o_cal_red a{color:#fff !important}.o_cal_rebeccapurple{background:#663399;border-color:#663399;color:#FFF}.o_cal_rebeccapurple .o_cal_wv_event_header{background:#663399}.o_cal_rebeccapurple a{color:#fff !important}.o_cal_grey{background:#DDDAAA;border-color:#5D5D5D;color:#FFF}.o_cal_grey .o_cal_wv_event_header{background:#5D5D5D}.o_cal_grey a{color:#fff !important}.o_cal_config_enabled,.o_cal_config_disabled{position:relative;float:left;display:inline}.o_cal_config_calendar{margin:0 5px;padding:1px 6px 1px 4px;position:relative;width:200px;overflow:hidden;float:left;display:inline}.o_cal_colorchooser_selected:before{content:"\f00c"}#o_cal_colorchooser div{border:1px solid #337ab7;margin:5px;display:inline-block}#o_cal_colorchooser div:hover{border:1px solid #333}#o_cal_colorchooser a{width:20px;height:20px;display:inline-block}.fc-button{color:#333;background-color:#fff;border-color:#ccc}.fc-button:hover,.fc-button:focus,.fc-button.focus,.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{color:#333;background-color:#e6e6e6;border-color:#adadad}.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{background-image:none}.fc-button.disabled,.fc-button.disabled:hover,.fc-button.disabled:focus,.fc-button.disabled.focus,.fc-button.disabled:active,.fc-button.disabled.active,.fc-button[disabled],.fc-button[disabled]:hover,.fc-button[disabled]:focus,.fc-button[disabled].focus,.fc-button[disabled]:active,.fc-button[disabled].active,fieldset[disabled] .fc-button,fieldset[disabled] .fc-button:hover,fieldset[disabled] .fc-button:focus,fieldset[disabled] .fc-button.focus,fieldset[disabled] .fc-button:active,fieldset[disabled] .fc-button.active{background-color:#fff;border-color:#ccc}.fc-button .badge{color:#fff;background-color:#333}.fc-button.fc-state-default{text-shadow:none}.fc-button.fc-state-active{color:#fff;background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active:hover,.fc-button.fc-state-active:focus,.fc-button.fc-state-active.focus,.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{background-image:none}.fc-button.fc-state-active.disabled,.fc-button.fc-state-active.disabled:hover,.fc-button.fc-state-active.disabled:focus,.fc-button.fc-state-active.disabled.focus,.fc-button.fc-state-active.disabled:active,.fc-button.fc-state-active.disabled.active,.fc-button.fc-state-active[disabled],.fc-button.fc-state-active[disabled]:hover,.fc-button.fc-state-active[disabled]:focus,.fc-button.fc-state-active[disabled].focus,.fc-button.fc-state-active[disabled]:active,.fc-button.fc-state-active[disabled].active,fieldset[disabled] .fc-button.fc-state-active,fieldset[disabled] .fc-button.fc-state-active:hover,fieldset[disabled] .fc-button.fc-state-active:focus,fieldset[disabled] .fc-button.fc-state-active.focus,fieldset[disabled] .fc-button.fc-state-active:active,fieldset[disabled] .fc-button.fc-state-active.active{background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active .badge{color:#337ab7;background-color:#fff}.o_visual{position:absolute;top:0;left:0;overflow:hidden;height:120px;width:180px;vertical-align:middle}@media (min-width: 768px) and (max-width: 991px){.o_visual{height:80px;width:120px}}@media (max-width: 767px){.o_visual{height:50px;width:75px}}.o_visual img{width:100%;height:auto}.o_visual .o_visual_not_available{width:100%;height:100%;background-image:url("../light/images/no_preview.png");background-repeat:no-repeat;background-position:50% 50%;background-size:contain}.o_coursetable.o_rendertype_custom .o_table_row{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_coursetable.o_rendertype_custom .o_table_row .o_visual{border-right:1px solid #337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_access{position:absolute;top:0;right:0;height:120px;width:180px;overflow:hidden;border-left:1px solid #337ab7;padding-top:0.25em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{padding:0 1em;height:20px;line-height:20px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{position:relative;left:2px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score .o_label{color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social{position:absolute;width:100%;bottom:32px;height:20px;padding-left:1em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_title,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating o_rating_legend,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_explanation{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings{padding:0 0 0 1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label{margin-bottom:1em;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_methods{color:#5bc0de}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{position:absolute;display:block;bottom:0;width:90px;height:30px;line-height:30px;text-align:center}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{right:0}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start{color:#fff;background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active{background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start .badge{color:#337ab7;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{color:#fff;background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active{background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book .badge{color:#f0ad4e;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:90px;color:#fff;background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active{background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details .badge{color:#5cb85c;background-color:#fff}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{height:80px;width:120px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_comments,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_label{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{width:60px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:60px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:120px;margin:0 180px 0 180px;position:relative;padding:1em 0.5em 0.25em 1em;overflow:hidden}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{margin:0;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{display:block;color:#337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover{color:#286090}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author{margin-top:0.5em;line-height:1em;font-size:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle{position:absolute;top:5px;right:40px;font-size:90%;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#337ab7}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #337ab7;border-bottom:1px solid #337ab7}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_level .o_meta .o_title a:hover{color:#286090}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels_list .o_sublevel{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_catalog .o_sublevels_list .o_sublevel .o_visual{height:75px;width:75px}.o_catalog .o_sublevels_list .o_sublevel .o_title{margin:0}.o_catalog .o_sublevels_list .o_sublevel .o_meta{border-left:1px solid #337ab7;min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_title{line-height:75px}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_desc{display:none}.o_catalog .o_sublevels_list .o_sublevel .o_meta h4.o_title>a,.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_cal .fc-header-title h2.o_title>a,.o_cal .fc-header-title .o_catalog .o_sublevels_list .o_sublevel .o_meta h2.o_title>a{font-family:inherit;font-weight:inherit}.o_catalog .o_sublevels_list .o_sublevel .o_meta h4.o_title>a>i,.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_cal .fc-header-title h2.o_title>a>i,.o_cal .fc-header-title .o_catalog .o_sublevels_list .o_sublevel .o_meta h2.o_title>a>i{display:none}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #337ab7;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #337ab7;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#337ab7;font-family:inherit;font-weight:inherit}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#286090}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a>i{display:none}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (min-width: 768px){.o_catalog .o_sublevels_list,.o_catalog .o_sublevels_compact{-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2;columns:2}}
 .o_repo_details{position:relative}.o_repo_details .o_lead{margin-bottom:10px}.o_repo_details .o_lead .o_author{margin-top:0.5em;margin-bottom:1em;font-size:120%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_repo_details .o_lead .o_media{float:right;margin-left:2em;margin-bottom:2em}.o_repo_details .o_lead h1 i{display:none}.o_repo_details .o_overview i{margin-right:0.5em}.o_repo_details .o_overview div{margin-bottom:0.25em}.o_repo_details .o_start,.o_repo_details .o_book{margin:2em 0}.o_repo_details .o_social:before,.o_repo_details .o_social:after{content:" ";display:table}.o_repo_details .o_social:after{clear:both}.o_repo_details .o_social .o_rating_wrapper{float:left}.o_repo_details .o_social .o_comments{margin-left:1em}@media (max-width: 767px){.o_repo_details .o_lead p{font-size:16px}.o_repo_details .o_lead .o_media{margin-left:0;float:none;text-align:center}}@media (max-width: 613px){.o_repo_details .o_subcolumn{width:100%}}
 .o_meta .o_closed{padding:2px 5px;margin:5px 0}.o_overview .o_closed{padding:12px 15px;margin:15px 0}.o_ac_configuration span.o_ac_infos{font-weight:normal;color:grey}.badge.o_midpub{background-color:#3c763d}.badge.o_midwarn{background-color:#8a6d3b}.badge.o_midlock{background-color:#31708f}.badge.o_miderr{background-color:#a94442}.badge.o_middel{background-color:#777}.o_course_editor_legend .badge{font-size:80%}.o_course_editor_legend .badge:before{content:none}.o_passed{color:#3c763d;font-weight:bold}.o_passed a:hover{color:#2b542c}.o_passed th{color:#333}.o_failed{color:#a94442;font-weight:bold}.o_failed a:hover{color:#66512c}.o_failed th{color:#333}.o_unknown{color:#8a6d3b;font-weight:bold}.o_unknown a:hover{color:#66512c}.o_unknown th{color:#333}.o_noinfo{color:#777}.o_course_run .o_toc .o_entry .o_shorttitle{border-bottom:1px solid #777}.o_course_run .o_toc .o_entry .o_displaytitle{margin-top:5px;color:#777}.o_course_run .o_toc .o_entry .o_objectives{margin-top:10px;font-style:italic}.o_course_run.o_titled_wrapper>h2 i{display:none}.o_tree.o_course_menu div.o_tree_l0>a:first-child{background-color:none}.o_st_peekview ul li{margin-bottom:0.5em}.o_cl_line{margin-bottom:10px;padding-bottom:5px}.o_cl_line.o_even{background-color:#f9f9f9}.o_ll_container h5{margin-bottom:5px}.o_ll_container h5 a.o_desc{color:#337ab7}.o_ll_container h5 a.o_desc small{display:none}.o_ll_container h5 a.o_desc:hover{color:#286090;text-decoration:none}.o_ll_container h5 a.o_desc:hover small{color:#5e5e5e;display:inline}.o_ll_container div.o_comment{color:#777}.o_cmembers .o_cmember{margin:12px 0}.o_cmembers .o_cmember .o_portrait{margin-right:10px}.o_cmembers .o_cmember .o_portrait img{width:50px;height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper{line-height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper .o_mail{margin-left:6px}table.table.o_qti_item_kprim>thead>tr>th,table.table.o_qti_item_kprim>tbody>tr>td{border:none}td.o_qti_item_kprim_input,th.o_qti_item_kprim_input{text-align:center}td.o_qti_item_kprim_input .radio,th.o_qti_item_kprim_input .radio{display:inline}div.o_qti_menu_section,div.o_qti_menu_section_clickable,div.o_qti_menu_section_active{margin-top:10px}div.o_qti_menu_item a,div.o_qti_menu_section a{text-decoration:none}div.o_qti_menu_item{padding:.1em}div.o_qti_menu_item_active{padding:.1em;font-weight:bold}div.o_qti_item_itemfeedback{background-color:#ffffff;border-color:#000000}div.o_qti_item_choice_option_flow{display:inline-block;padding:.5em;border:1px solid transparent}.d3chart .bar_green{fill:#5cb85c}.d3chart .bar_red{fill:#d9534f}.d3chart .bar_grey{fill:lightgrey}div.o_qti_statistics ul{list-style-type:none;padding:0;margin:0;font-size:90%}div.o_qti_statistics ul strong{font-weight:normal}div.o_qti_statistics ul li{padding-left:48px;margin-left:0;margin-bottom:10px}div.o_qti_statistics ul li.o_qti_statistics-ncorrect:before{font-size:125%;content:'\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-correct:before{font-size:125%;content:'\2713\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kplus:before{font-size:125%;content:'\2713\00A0\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kminus:before{font-size:125%;content:'\2A2F\00A0\2713\00A0\00A0'}div.o_qti_statistics ul li img{vertical-align:top}div.o_qti_statistics table.o_qti_statistics_figures tr{float:left}div.o_qti_statistics table.o_qti_statistics_figures tr:nth-child(2n+1){clear:left;padding-right:20px}div.o_qti_statistics table.o_qti_statistics_figures td{width:200px;padding-left:0}div.o_qti_statistics table.o_qti_statistics_figures td+td{width:100px}div.o_qti_statistics .o_qti_statistics_answer{background:#F5F5F5;padding:1px 2px;width:90%}div.o_qti_statistics div.o_qti_statistics_legend{padding-top:10px;width:470px;border:1px solid #ddd;border-radius:4px}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_green{background-color:#9dd53a}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_red{background-color:#f85032}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_grey{background-color:lightgrey}div.o_qti_metadatas .panel-body{border-top:none}.o_qti_menu_item_attempts:after,.o_qti_menu_item_attempts_marked:after{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_qti_menu_item_attempts:after{content:"\f11d"}.o_qti_menu_item_attempts_marked:after{content:"\f024";color:#337ab7}.onyx_iframe{width:100%;height:100%;border:none;min-height:60em}.o_qti_print div.o_qti_statistics{width:680px}@media print{div.o_qti_statistics{width:680px}}#o_dev_tool #o_dev_tool_mode{width:1em;height:1em;float:left;border:1px solid #000;margin-right:5px}a.o_dev{position:absolute;left:0;top:0;z-index:4000;background:#f0ad4e;border:1px solid #d59645;border-top:none;border-left:none;border-radius:0 0 4px 0;color:#fff}a.o_dev:hover{color:#d9534f}.o_dev_w{margin:1px}.o_dev_w .o_dev_h{color:#000;font-size:8px;line-height:10px;margin:0}.o_dev_w .o_dev_h span{background:#f4c37d;border:1px solid #f0ad4e;border-bottom:0}.o_dev_w .o_dev_c{position:relative;border:1px dotted #eee}.o_dev_w .o_dev_c .o_dev_i{position:absolute;top:0px;left:24px;height:auto;width:auto;padding:5px;border:1px solid black;display:none;margin:0px;z-index:999;font-size:11px;background-color:#BBF}.o_dev_w.o_dev_m>.o_dev_c{border:1px solid #f0ad4e;margin:0px;background-color:#f8e9d4}.o_wikimod_nav .o_noti{margin:0}.o_wikimod_editform_wrapper{margin-top:30px}.o_wiki-file-deleted{text-decoration:line-through}.o_ep_icon_map:before{content:"\f0b1"}.o_ep_icon_collection:before{content:"\f0b1"}.o_ep_icon_page:before{content:"\f016"}.o_ep_icon_struct:before{content:"\f1b3"}.o_ep_icon_liveblog:before{content:"\f0a1"}.o_artefact_closed:before{content:"\f023"}.o_portfolio_toc .o_ep_link{float:right;margin-right:0px}.o_portfolio_toc .o_ep_commentlink{float:right;margin-right:10%}.o_portfolio_toc li.level1{font-size:1.2em;margin:1.2em 0 0.2em 0;border-bottom:1px solid #ddd}.o_portfolio_toc li.level2{padding-left:20px;font-size:1.1em;border-bottom:1px dotted #ddd}.o_portfolio_toc li.level3{padding-left:40px}.o_eportfolio_page .o_eportfolio_structure>h5{border-bottom:1px solid #ddd;margin-top:1.2em}.o_eportfolio_maps .panel{font-family:'Century Gothic', 'Apple Gothic', sans-serif;box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .panel-heading{padding:5px 10px}.o_eportfolio_maps h4,.o_eportfolio_maps .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps h2{padding:11px 15px;background:rgba(255,255,230,0.7) none;border-radius:6px}.o_eportfolio_maps .table>tbody>tr>td{border-top:none}.o_eportfolio_maps .panel-body{border-top:none}.o_eportfolio_maps .panel>.panel-body+.table{border-top:none}.panel-footer .o_ep_options{display:inline-block}.o_eportfolio_map{padding:0 20px 2px 3px;border-radius:6px 10px 6px 0;font-family:'Century Gothic', 'Apple Gothic', sans-serif}.o_map_header{padding-left:5px}.o_eportfolio_map ul.nav-tabs li:not(.active) a{background-color:rgba(240,240,240,0.7);border-radius:4px 4px 0 0}.o_eportfolio_edit{border-radius:4px 4px 0 0}.o_ep_actualpage,.o_eportfolio_edit{padding:15px;background-color:#fff}.o_ep_content{margin-top:15px}.o_ep_filter .o_date.form-inline .form-group,.o_ep_filter .o_date.o_navbar-form .form-group{margin-left:8px}.o_eportfolio_share_policy_wrapper{border:1px solid #ddd;border-radius:4px}.o_eportfolio_share_header{padding:10px 15px;border-bottom:1px solid #ddd;background-color:#f5f5f5}.o_eportfolio_share_policy{padding:10px 15px}.o_map-default{background:#fafafa;background:#fafafa -webkit-gradient(linear, 37% 20%, 53% 100%, from(#fafafa), to(#efefef));background:#fafafa -moz-linear-gradient(43% 71% 101deg, #efefef, #fafafa);background:#fafafa -o-linear-gradient(#fafafa, #efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa', EndColorStr='#efefef');border:1px solid #efefef;border-left:3px solid rgba(188,188,188,0.8)}.o_eportfolio_maps .o_map-default h4,.o_eportfolio_maps .o_map-default .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-default h2{color:#444;background:none}.o_eportfolio_maps .o_map-default .panel-body,.o_eportfolio_maps .o_map-default td,.o_eportfolio_maps .o_map-default a{color:#000}.o_map-comic{background:#a2c3e8 none;font-family:'Comic Sans MS', 'Comic Sans', fantasy;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_map-leather{background-color:#957352;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(248,248,248,0.7)), color-stop(100%, rgba(193,193,193,0.5))),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-webkit-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-moz-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-ms-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-o-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");font-family:Palatino, Georgia, serif;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-leather h4,.o_eportfolio_maps .o_map-leather .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-leather h2{background:rgba(243,230,225,0.3) none}.o_eportfolio_maps .o_map-leather .panel-body,.o_eportfolio_maps .o_map-leather td{color:#333}.o_eportfolio_maps .o_map-leather a{color:#fad9a4}.o_eportfolio_map.o_map-leather .o_map_header h4,.o_eportfolio_map.o_map-leather .o_map_header .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_map.o_map-leather .o_map_header h2,.o_eportfolio_map.o_map-leather .o_map_header p,.o_eportfolio_map.o_map-leather .o_map_header a,.o_eportfolio_map.o_map-leather .o_map_header span,.o_eportfolio_map.o_map-leather .o_map_header label{color:#333}.o_map-epmst-green{background-color:#ecf69a;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-green h4,.o_eportfolio_maps .o_map-epmst-green .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green h2{color:#444}.o_eportfolio_maps .o_map-epmst-green .panel-body,.o_eportfolio_maps .o_map-epmst-green td,.o_eportfolio_maps .o_map-epmst-green a{color:#000}.o_map-epmst-green2{background:#99e44d;background:#99e44d -webkit-gradient(linear, 37% 20%, 53% 100%, from(#99e44d), to(#cbf1a5));background:#99e44d -moz-linear-gradient(43% 71% 101deg, #cbf1a5, #99e44d);background:#99e44d -o-linear-gradient(#99e44d, #cbf1a5);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#99e44d', EndColorStr='#cbf1a5');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green2 h4,.o_eportfolio_maps .o_map-epmst-green2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green2 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green2 .panel-body,.o_eportfolio_maps .o_map-epmst-green2 td,.o_eportfolio_maps .o_map-epmst-green2 a{color:#000}.o_map-epmst-green3{background:#dff0c1;background:#dff0c1 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dff0c1), to(#a0d346));background:#dff0c1 -moz-linear-gradient(43% 71% 101deg, #a0d346, #dff0c1);background:#dff0c1 -o-linear-gradient(#dff0c1, #a0d346);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dff0c1', EndColorStr='#a0d346');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green3 h4,.o_eportfolio_maps .o_map-epmst-green3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green3 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green3 .panel-body,.o_eportfolio_maps .o_map-epmst-green3 td,.o_eportfolio_maps .o_map-epmst-green3 a{color:#000}.o_map-epmst-green4{background-color:#d7dbb5;border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green4 h4,.o_eportfolio_maps .o_map-epmst-green4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green4 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green4 .panel-body,.o_eportfolio_maps .o_map-epmst-green4 td,.o_eportfolio_maps .o_map-epmst-green4 a{color:#000}.o_map-epmst-red{background:#ffba71;background:#ffba71 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffba71), to(#ffba99));background:#ffba71 -moz-linear-gradient(43% 71% 101deg, #ffba99, #ffba71);background:#ffba71 -o-linear-gradient(#ffba71, #ffba99);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffba71', EndColorStr='#ffba99');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red h4,.o_eportfolio_maps .o_map-epmst-red .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red h2{color:#444}.o_eportfolio_maps .o_map-epmst-red .panel-body,.o_eportfolio_maps .o_map-epmst-red td,.o_eportfolio_maps .o_map-epmst-red a{color:#000}.o_map-epmst-red2{background:#ff9772;background:#ff9772 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ff9772), to(#ff9780));background:#ff9772 -moz-linear-gradient(43% 71% 101deg, #ff9780, #ff9772);background:#ff9772 -o-linear-gradient(#ff9772, #ff9780);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ff9772', EndColorStr='#ff9780');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red2 h4,.o_eportfolio_maps .o_map-epmst-red2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red2 .panel-body,.o_eportfolio_maps .o_map-epmst-red2 td,.o_eportfolio_maps .o_map-epmst-red2 a{color:#000}.o_map-epmst-red3{background:#e8afbb;background:#e8afbb -webkit-gradient(linear, 37% 20%, 53% 100%, from(#e8afbb), to(#e8afa0));background:#e8afbb -moz-linear-gradient(43% 71% 101deg, #e8afa0, #e8afbb);background:#e8afbb -o-linear-gradient(#e8afbb, #e8afa0);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#e8afbb', EndColorStr='#e8afa0');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red3 h4,.o_eportfolio_maps .o_map-epmst-red3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red3 .panel-body,.o_eportfolio_maps .o_map-epmst-red3 td,.o_eportfolio_maps .o_map-epmst-red3 a{color:#000}.o_map-epmst-red4{background:#ffa800;background:#ffa800 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffa800), to(#ffaf00));background:#ffa800 -moz-linear-gradient(43% 71% 101deg, #ffaf00, #ffa800);background:#ffa800 -o-linear-gradient(#ffa800, #ffaf00);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffa800', EndColorStr='#ffaf00');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red4 h4,.o_eportfolio_maps .o_map-epmst-red4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red4 .panel-body,.o_eportfolio_maps .o_map-epmst-red4 td,.o_eportfolio_maps .o_map-epmst-red4 a{color:#000}.o_map-epmst-blue{background:#00d2f8;background:#00d2f8 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#00d2f8), to(#4a9ead));background:#00d2f8 -moz-linear-gradient(43% 71% 101deg, #4a9ead, #00d2f8);background:#00d2f8 -o-linear-gradient(#00d2f8, #4a9ead);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#00d2f8', EndColorStr='#4a9ead');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue h4,.o_eportfolio_maps .o_map-epmst-blue .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue .panel-body,.o_eportfolio_maps .o_map-epmst-blue td,.o_eportfolio_maps .o_map-epmst-blue a{color:#000}.o_map-epmst-blue2{background-color:#c4f6ff;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue2 h4,.o_eportfolio_maps .o_map-epmst-blue2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue2 .panel-body,.o_eportfolio_maps .o_map-epmst-blue2 td,.o_eportfolio_maps .o_map-epmst-blue2 a{color:#000}.o_map-epmst-blue3{background-color:#b3e2f7;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue3{box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .o_map-epmst-blue3 h4,.o_eportfolio_maps .o_map-epmst-blue3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue3 .panel-body,.o_eportfolio_maps .o_map-epmst-blue3 td,.o_eportfolio_maps .o_map-epmst-blue3 a{color:#000}.o_map-epmst-blue4{background:#dee7f7;background:#dee7f7 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dee7f7), to(#c1e9fd));background:#dee7f7 -moz-linear-gradient(43% 71% 101deg, #c1e9fd, #dee7f7);background:#dee7f7 -o-linear-gradient(#dee7f7, #c1e9fd);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dee7f7', EndColorStr='#c1e9fd');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue4 h4,.o_eportfolio_maps .o_map-epmst-blue4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue4 .panel-body,.o_eportfolio_maps .o_map-epmst-blue4 td,.o_eportfolio_maps .o_map-epmst-blue4 a{color:#000}.o_userbulk_changedcell{font-style:italic;font-weight:bold}body.o_dmz{background:transparent}body.o_dmz #o_bg{position:absolute;top:0;left:0;width:100%;height:100%;border-top:50px solid transparent;border-bottom:70px solid transparent;background:url("../light/images/learn-bg.jpg");background:linear-gradient(to right, rgba(255,255,255,0.1) 0.2%, rgba(255,255,255,0.6) 60%, rgba(255,255,255,0.8) 100%),url("../light/images/learn-bg.jpg");background-size:cover, cover;background-position:center center,center center;background-repeat:no-repeat}body.o_dmz #o_main_wrapper,body.o_dmz #o_main_wrapper #o_main_container{background:transparent}.o_login{padding-bottom:20px;padding-left:10%;padding-right:10%;text-align:right}.o_login .o_login_intro{padding-left:10%}.o_login .o_login_intro h1{margin-bottom:40px;color:#337ab7}.o_login .o_login_intro .lead{color:#333}.o_login .o_login_intro .lead h1,.o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h3,.o_login .o_login_intro .lead h4,.o_login .o_login_intro .lead .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h5{margin-bottom:20px;color:#337ab7}.o_login .o_login_messages,.o_login .o_login_box{display:inline-block;width:400px;text-align:left}.o_login .o_login_messages .o_infomessage_wrapper{background:rgba(255,255,255,0.5);border:1px solid transparent;border-radius:4px;padding:6px 12px}.o_login .o_login_messages .o_infomessage_wrapper .o_info,.o_login .o_login_messages .o_infomessage_wrapper .o_warning,.o_login .o_login_messages .o_infomessage_wrapper .o_note{margin:0}.o_login .o_login_box{padding-top:10px}.o_login .o_login_providers{margin-bottom:6px;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_providers a span{display:block;font-size:9px;padding-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_login .o_login_providers .o_icon_provider_olat{font-size:1em}.o_login .o_login_provider{background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_form{position:relative;padding:10px 12px}.o_login .o_login_form .o_login_pwd{position:absolute;bottom:2em;right:12px}.o_login .o_login_form .o_form .o_desc{margin:0 0 30px 0;padding:0;border-left:0;background-color:transparent}.o_login .o_login_register{display:block;line-height:2em;font-size:18px;text-align:center;color:#fff;background-color:#5bc0de;border-color:#46b8da;border-radius:4px;margin-top:16px;padding:10px 12px}.o_login .o_login_register:hover,.o_login .o_login_register:focus,.o_login .o_login_register.focus,.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#269abc}.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{background-image:none}.o_login .o_login_register.disabled,.o_login .o_login_register.disabled:hover,.o_login .o_login_register.disabled:focus,.o_login .o_login_register.disabled.focus,.o_login .o_login_register.disabled:active,.o_login .o_login_register.disabled.active,.o_login .o_login_register[disabled],.o_login .o_login_register[disabled]:hover,.o_login .o_login_register[disabled]:focus,.o_login .o_login_register[disabled].focus,.o_login .o_login_register[disabled]:active,.o_login .o_login_register[disabled].active,fieldset[disabled] .o_login .o_login_register,fieldset[disabled] .o_login .o_login_register:hover,fieldset[disabled] .o_login .o_login_register:focus,fieldset[disabled] .o_login .o_login_register.focus,fieldset[disabled] .o_login .o_login_register:active,fieldset[disabled] .o_login .o_login_register.active{background-color:#5bc0de;border-color:#46b8da}.o_login .o_login_register .badge{color:#5bc0de;background-color:#fff}.o_login .o_login_register small{font-size:14px}.o_login .o_login_social{position:relative;padding:10px 12px}.o_login .o_login_social li{padding:10px 12px}.o_login .o_login_social li>a{display:block;line-height:2em;text-align:center;font-size:18px;border-radius:4px;padding:10px 12px}.o_login .o_login_social .btn-default.o_sel_auth_facebook{color:#fff;background-color:#4568b2;border-color:#3e5da0}.o_login .o_login_social .btn-default.o_sel_auth_facebook:hover,.o_login .o_login_social .btn-default.o_sel_auth_facebook:focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook.focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook:active,.o_login .o_login_social .btn-default.o_sel_auth_facebook.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_facebook.dropdown-toggle{color:#fff;background-color:#37538d;border-color:#2d4374}.o_login .o_login_social .btn-default.o_sel_auth_facebook:active,.o_login .o_login_social .btn-default.o_sel_auth_facebook.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_facebook.dropdown-toggle{background-image:none}.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled,.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled:hover,.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled:focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled.focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled:active,.o_login .o_login_social .btn-default.o_sel_auth_facebook.disabled.active,.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled],.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled]:hover,.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled]:focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled].focus,.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled]:active,.o_login .o_login_social .btn-default.o_sel_auth_facebook[disabled].active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook:hover,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook:focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook.focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook:active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_facebook.active{background-color:#4568b2;border-color:#3e5da0}.o_login .o_login_social .btn-default.o_sel_auth_facebook .badge{color:#4568b2;background-color:#fff}.o_login .o_login_social .btn-default.o_sel_auth_twitter{color:#fff;background-color:#2cc5ff;border-color:#13beff}.o_login .o_login_social .btn-default.o_sel_auth_twitter:hover,.o_login .o_login_social .btn-default.o_sel_auth_twitter:focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter.focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter:active,.o_login .o_login_social .btn-default.o_sel_auth_twitter.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_twitter.dropdown-toggle{color:#fff;background-color:#00b4f8;border-color:#009ad4}.o_login .o_login_social .btn-default.o_sel_auth_twitter:active,.o_login .o_login_social .btn-default.o_sel_auth_twitter.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_twitter.dropdown-toggle{background-image:none}.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled,.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled:hover,.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled:focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled.focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled:active,.o_login .o_login_social .btn-default.o_sel_auth_twitter.disabled.active,.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled],.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled]:hover,.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled]:focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled].focus,.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled]:active,.o_login .o_login_social .btn-default.o_sel_auth_twitter[disabled].active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter:hover,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter:focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter.focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter:active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_twitter.active{background-color:#2cc5ff;border-color:#13beff}.o_login .o_login_social .btn-default.o_sel_auth_twitter .badge{color:#2cc5ff;background-color:#fff}.o_login .o_login_social .btn-default.o_sel_auth_google{color:#fff;background-color:#e15f4f;border-color:#dd4b39}.o_login .o_login_social .btn-default.o_sel_auth_google:hover,.o_login .o_login_social .btn-default.o_sel_auth_google:focus,.o_login .o_login_social .btn-default.o_sel_auth_google.focus,.o_login .o_login_social .btn-default.o_sel_auth_google:active,.o_login .o_login_social .btn-default.o_sel_auth_google.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_google.dropdown-toggle{color:#fff;background-color:#d83825;border-color:#ba3120}.o_login .o_login_social .btn-default.o_sel_auth_google:active,.o_login .o_login_social .btn-default.o_sel_auth_google.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_google.dropdown-toggle{background-image:none}.o_login .o_login_social .btn-default.o_sel_auth_google.disabled,.o_login .o_login_social .btn-default.o_sel_auth_google.disabled:hover,.o_login .o_login_social .btn-default.o_sel_auth_google.disabled:focus,.o_login .o_login_social .btn-default.o_sel_auth_google.disabled.focus,.o_login .o_login_social .btn-default.o_sel_auth_google.disabled:active,.o_login .o_login_social .btn-default.o_sel_auth_google.disabled.active,.o_login .o_login_social .btn-default.o_sel_auth_google[disabled],.o_login .o_login_social .btn-default.o_sel_auth_google[disabled]:hover,.o_login .o_login_social .btn-default.o_sel_auth_google[disabled]:focus,.o_login .o_login_social .btn-default.o_sel_auth_google[disabled].focus,.o_login .o_login_social .btn-default.o_sel_auth_google[disabled]:active,.o_login .o_login_social .btn-default.o_sel_auth_google[disabled].active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google:hover,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google:focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google.focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google:active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_google.active{background-color:#e15f4f;border-color:#dd4b39}.o_login .o_login_social .btn-default.o_sel_auth_google .badge{color:#e15f4f;background-color:#fff}.o_login .o_login_social .btn-default.o_sel_auth_linkedin{color:#fff;background-color:#0181bd;border-color:#0170a4}.o_login .o_login_social .btn-default.o_sel_auth_linkedin:hover,.o_login .o_login_social .btn-default.o_sel_auth_linkedin:focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin:active,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_linkedin.dropdown-toggle{color:#fff;background-color:#015e8a;border-color:#014667}.o_login .o_login_social .btn-default.o_sel_auth_linkedin:active,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_linkedin.dropdown-toggle{background-image:none}.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled:hover,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled:focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled.focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled:active,.o_login .o_login_social .btn-default.o_sel_auth_linkedin.disabled.active,.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled],.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled]:hover,.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled]:focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled].focus,.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled]:active,.o_login .o_login_social .btn-default.o_sel_auth_linkedin[disabled].active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin:hover,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin:focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin.focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin:active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_linkedin.active{background-color:#0181bd;border-color:#0170a4}.o_login .o_login_social .btn-default.o_sel_auth_linkedin .badge{color:#0181bd;background-color:#fff}.o_login .o_login_social .btn-default.o_sel_auth_adfs{color:#fff;background-color:#1a1a1a;border-color:#0d0d0d}.o_login .o_login_social .btn-default.o_sel_auth_adfs:hover,.o_login .o_login_social .btn-default.o_sel_auth_adfs:focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs.focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs:active,.o_login .o_login_social .btn-default.o_sel_auth_adfs.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_adfs.dropdown-toggle{color:#fff;background-color:#000;border-color:#000}.o_login .o_login_social .btn-default.o_sel_auth_adfs:active,.o_login .o_login_social .btn-default.o_sel_auth_adfs.active,.open>.o_login .o_login_social .btn-default.o_sel_auth_adfs.dropdown-toggle{background-image:none}.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled,.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled:hover,.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled:focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled.focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled:active,.o_login .o_login_social .btn-default.o_sel_auth_adfs.disabled.active,.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled],.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled]:hover,.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled]:focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled].focus,.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled]:active,.o_login .o_login_social .btn-default.o_sel_auth_adfs[disabled].active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs:hover,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs:focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs.focus,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs:active,fieldset[disabled] .o_login .o_login_social .btn-default.o_sel_auth_adfs.active{background-color:#1a1a1a;border-color:#0d0d0d}.o_login .o_login_social .btn-default.o_sel_auth_adfs .badge{color:#1a1a1a;background-color:#fff}@media (max-width: 767px){body.o_dmz #o_bg{background:none;display:none}.o_login{padding:0}.o_login .o_login_intro{padding:0;text-align:left}.o_login .o_login_box_wrapper{text-align:center;padding:0}.o_login .o_login_box{padding-left:0;padding-right:0}.o_login .o_login_box .o_login_providers,.o_login .o_login_box .o_login_provider{-webkit-box-shadow:none;box-shadow:none}.o_login .o_login_messages,.o_login .o_login_box{width:100%;display:block}}.o_home_main h1{text-align:center}.o_home_main .o_icon_rss{line-height:20px;vertical-align:middle}.o_showall{font-size:12px;text-align:right;margin-bottom:5px;margin-top:10px}.o_portlet{position:relative;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1)}.o_portlet .o_header{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:6px 12px;border-bottom:1px solid #ddd;background-color:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_portlet .o_content{padding:6px 12px}.o_portlet .o_portlet_table{margin:-12px;margin-bottom:-6px;margin-top:0}.o_portlet .o_table_empty.o_info{padding:6px}.o_portlet .o_toolbox{position:absolute;top:-1px;right:-1px;z-index:2;background-color:#fff;border:1px solid #faebcc;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:6px 12px}.o_portlet .o_toolbox div{display:inline}.o_portlet .o_edit_shim{position:absolute;height:100%;width:100%;z-index:1;background:#fcf8e3;opacity:0.8}.o_inactive .o_header a{float:right;margin-left:12px;margin-top:10px}.o_portlet_dyk_q{margin-top:5px;font-style:italic}.o_portlet_dyk_a{margin:5px 0}.o_portlet_dyk_next{margin:5px 0;text-align:right}.o_library_icon:before{content:"\f19c"}.o_library ul{list-style:none;margin:0 0 15px 0;padding:0}.o_library ul ul{margin:0}.o_library_overview .o_library_newest_files ul li{float:left;margin-right:15px}.o_library_item{margin-bottom:10px;position:relative}.o_library_item .o_library_visual,.o_library_item .o_library_extra,.o_library_item .o_library_meta{margin-top:15px}.o_library_item .o_library_visual{float:left;background-color:#fff;border-radius:4px;border:1px solid #ddd}.o_library_item .o_library_visual .o_thumbnail_available,.o_library_item .o_library_visual .o_thumbnail_unavailable{background-size:146px auto;width:150px !important;height:150px !important;background-repeat:no-repeat;background-position:50% 50%}.o_library_item .o_library_visual .o_thumbnail_available:before,.o_library_item .o_library_visual .o_thumbnail_unavailable:before{content:none}.o_library_item .o_library_visual .o_thumbnail_available{background-size:146px auto}.o_library_item .o_library_visual .o_thumbnail_unavailable{display:none}.o_library_item .o_library_extra{float:right;width:200px}.o_library_item .o_library_meta{clear:both}.o_library_item .o_library_meta .o_library_desc{padding-bottom:10px}.o_library_item .o_library_meta small{display:block;word-wrap:break-word}.o_library_item h4,.o_library_item .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item h2{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:normal}.o_library_item .btn{display:block;margin-bottom:0.5em}.o_library_item .o_comments{display:inline-block}.o_library_item .table{table-layout:fixed;word-wrap:break-word;margin-bottom:0}.o_library_item p.o_library_show_more{text-align:right;margin:0;padding-top:20px}.o_library_item .o_library_more{padding-top:20px;display:none}.o_library_folder{margin-top:-20px}.o_ratings_and_comments .o_rating_title,.o_ratings_and_comments .o_rating_explanation{display:none}@media (min-width: 768px){.o_library_item .o_library_meta{clear:none;margin-left:150px;margin-right:200px;padding:0 10px}.o_library_item .o_library_more{display:none}.o_library_item .o_library_more table tbody{vertical-align:top}.o_library_item .o_library_more table tr,.o_library_item .o_library_more table th,.o_library_item .o_library_more table td{display:inline-block}.o_library_item .o_library_more table tr{width:49%}.o_library_item .o_library_more table th{width:30%}.o_library_item .o_library_more table td{width:70%}}.o_library_item_compact .o_library_extra{width:auto}.o_library_item_compact .o_library_meta{padding:0 10px 0 0;margin:0;overflow:hidden}.o_library_item_compact .btn{display:inline-block}.o_library_item_compact h4,.o_library_item_compact .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item_compact h2{overflow:hidden;margin-right:70px}.o_library_item_compact h4 a,.o_library_item_compact .o_cal .fc-header-title h2 a,.o_cal .fc-header-title .o_library_item_compact h2 a{text-overflow:ellipsis;white-space:nowrap}.o_library_item_compact p.o_library_show_more{padding:20px;position:absolute;top:0;right:0}span.o_translation_i18nitem{position:relative !important}span.o_translation_i18nitem a.o_translation_i18nitem_launcher{position:absolute !important;z-index:100 !important;width:18px !important;height:20px !important;top:0 !important;left:5px !important;background:#fff;border:1px solid #337ab7 !important;border-radius:3px;text-align:center;padding:0 !important}.o_user_infos{position:relative}.o_user_infos .o_user_portrait{position:absolute;top:0;left:15px;width:100px;height:100px}.o_user_infos .o_user_infos_inner{margin:0 30px 0 100px}.o_user_infos .o_user_infos_inner table{margin:0 30px 15px 30px}.o_members_pagination{text-align:center}.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:66px;height:66px;margin-right:10px}@media (max-width: 767px){.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:50px;height:50px;margin:5px 5px 0 0}}.ui-widget{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:100%}.ui-widget-header{border-top:none;border-left:none;border-right:none;border-bottom:1px solid #eee;background:#fff;font-weight:bold}.ui-icon,.ui-widget-content .ui-icon,.ui-widget-header .ui-icon,.ui-state-default .ui-icon,.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-state-active .ui-icon,.ui-state-highlight .ui-icon,.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background:none;background-image:none}.ui-dialog{-webkit-box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);background-color:#fefefe}.ui-dialog .ui-widget-header .ui-dialog-title{color:#337ab7;font-weight:500;font-family:inherit;line-height:1.1}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close:before{content:"\f00d" !important}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;font-size:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close span{display:none}.ui-dialog .ui-widget-header .ui-button.ui-corner-all{border:none !important;background:#fff !important;float:right}.ui-dialog .ui-widget-content{border-color:#fff;padding:5px;overflow:auto;background:white !important}.ui-dialog .ui-dialog-titlebar{padding:4px 7px 4px 7px;background-color:#eee !important}.ui-dialog.ui-corner-all{border-radius:4px}.ui-dialog.ui-widget-content{border:1px solid transparent}.ui-dialog.o_modal-ui div.ui-dialog-buttonpane{display:none}.ui-datepicker{z-index:2000 !important;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.ui-datepicker .ui-widget-header .ui-corner-all,.ui-datepicker .ui-widget-header .ui-datepicker-next.ui-corner-all{border:none !important;background:#fff !important}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e:before{content:"\f061";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w:before{content:"\f060";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e,.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w{font-family:'FontAwesome';display:inline-block;background-image:none;background-position:0 0;font-weight:normal;text-indent:0;color:white}.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-next-hover{top:2px}.ui-datepicker .ui-state-default{background:#eee}.ui-datepicker .ui-state-highlight,.ui-datepicker .ui-widget-content .ui-state-highlight{border:1px solid #2e6da4;background:#337ab7;color:#fff}.ui-datepicker.ui-corner-all{border-radius:4px}.ui-datepicker.ui-widget-content{border:1px solid transparent}label.mce-label{display:inline;max-width:150px;margin-bottom:0;font-weight:normal}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}body.o_dmz{background:white !important}.progress{-webkit-print-color-adjust:exact;background-color:rgba(0,0,0,0.1) !important;border:1px solid rgba(0,0,0,0.5)}.progress-bar{-webkit-print-color-adjust:exact;background-color:#000 !important;border:10px solid #000}}body.o_browser_ie7 #o_offcanvas_right,body.o_browser_ie8 #o_offcanvas_right{right:0px}
\ No newline at end of file
diff --git a/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java b/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java
index 68ddbe2d438916fa3354d197b7b11b8abbf485b5..aeeeb375ce00ab63922dd7c1c719ef2750c19058 100644
--- a/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java
+++ b/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java
@@ -30,6 +30,7 @@ import org.apache.commons.io.FileUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.olat.core.gui.translator.Translator;
+import org.olat.ims.qti.editor.QTIEditHelper;
 import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion;
 import org.olat.ims.qti.editor.beecom.objects.FIBQuestion;
 import org.olat.ims.qti.editor.beecom.objects.FIBResponse;
@@ -102,6 +103,12 @@ public class CSVToQuestionConverterTest {
 		Assert.assertFalse(responses.get(4).isCorrect());
 		Assert.assertFalse(responses.get(5).isCorrect());
 		Assert.assertFalse(responses.get(6).isCorrect());
+
+		String feedbackMastery = QTIEditHelper.getFeedbackMasteryText(item);
+		Assert.assertEquals("Bravo! Die Antwort ich absolut korrekt.", feedbackMastery);
+		String feedbackFail = QTIEditHelper.getFeedbackFailText(item);
+		Assert.assertEquals("Leider falsch. Probieren Sie es noch einmal.", feedbackFail);
+		
 	}
 	
 	@Test
diff --git a/src/test/java/org/olat/ims/qti/questionimport/question_import_mc.txt b/src/test/java/org/olat/ims/qti/questionimport/question_import_mc.txt
index 5c569c3a509b6afba3d6a00e8b581a0bf030893d..5a2849f149853fe134b12d5443a10a3430596770 100644
--- a/src/test/java/org/olat/ims/qti/questionimport/question_import_mc.txt
+++ b/src/test/java/org/olat/ims/qti/questionimport/question_import_mc.txt
@@ -5,6 +5,8 @@ Titel	Fussball: Austragungsort
 Beschreibung	Die Fussball WM wird alle vier Jahre von einem anderen Land ausgerichtet.	
 Frage	In welchen Ländern wurde zwischen dem Jahr 2000 und 2015 eine Fussball Weltmeisterschaft ausgetragen?	
 Subject	/Sprache/Deutsch/Grammar/Komma
+Feedback correct answer	Bravo! Die Antwort ich absolut korrekt.
+Feedback wrong answer	Leider falsch. Probieren Sie es noch einmal.
 Punkte	3	
 1	Deutschland	
 1	Brasilien	
diff --git a/src/test/java/org/olat/modules/reminder/ReminderModuleTest.java b/src/test/java/org/olat/modules/reminder/ReminderModuleTest.java
index 6a0b4372ff24604a9505ddd96cedb35ae01014b9..a212cb8599ea76d9b28a25f12c02692bd1eef5a6 100644
--- a/src/test/java/org/olat/modules/reminder/ReminderModuleTest.java
+++ b/src/test/java/org/olat/modules/reminder/ReminderModuleTest.java
@@ -62,6 +62,8 @@ public class ReminderModuleTest extends OlatTestCase {
 	@Test
 	public void testCronJob_everyHeightHours() throws ParseException {
 		reminderModule.setScheduler("8", "6:30");
+		sleep(1000);
+		
 		String cron = reminderModule.getCronExpression();
 		
 		Calendar cal = Calendar.getInstance();
diff --git a/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java b/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java
index 903c86d864f8013284e5ab6c535fca7189d24c1e..52bbff217fe5cac64b525a5a26e3b0522430e810 100644
--- a/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java
+++ b/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java
@@ -19,15 +19,22 @@
  */
 package org.olat.modules.reminder.manager;
 
+import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.modules.reminder.Reminder;
 import org.olat.modules.reminder.SentReminder;
+import org.olat.modules.reminder.model.ReminderInfos;
+import org.olat.modules.reminder.model.SentReminderImpl;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.manager.RepositoryEntryRelationDAO;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -44,6 +51,8 @@ public class ReminderDAOTest extends OlatTestCase {
 	private DB dbInstance;
 	@Autowired
 	private ReminderDAO reminderDao;
+	@Autowired
+	private RepositoryEntryRelationDAO repositoryEntryRelationDao;
 	
 	@Test
 	public void createAndPersistReminder() {
@@ -110,5 +119,302 @@ public class ReminderDAOTest extends OlatTestCase {
 		Assert.assertEquals(id, sentReminder.getIdentity());
 		Assert.assertEquals(savedReminder, sentReminder.getReminder());
 	}
-
+	
+	@Test
+	public void getReminders_startDate() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-3");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 3);
+		Assert.assertNotNull(savedReminder);
+		dbInstance.commitAndCloseSession();
+		
+		Date now = new Date();
+		boolean found = false;
+		List<Reminder> loadedReminders = reminderDao.getReminders(now);
+		for(Reminder loadedReminder:loadedReminders) {
+			if(loadedReminder.equals(savedReminder)) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);	
+	}
+	
+	@Test
+	public void getReminders_repositoryEntry() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-4");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder reminder = reminderDao.createReminder(entry, creator);
+		reminder.setConfiguration("<rules></rules>");
+		reminder.setDescription("Reminder - 4");
+		reminder.setEmailBody("Hello world");
+		Reminder savedReminder = reminderDao.save(reminder);
+		Assert.assertNotNull(savedReminder);
+		dbInstance.commitAndCloseSession();
+		
+		List<Reminder> loadedReminders = reminderDao.getReminders(entry);
+		Assert.assertNotNull(loadedReminders);
+		Assert.assertEquals(1, loadedReminders.size());
+		
+		Reminder loadedReminder = loadedReminders.get(0);
+		Assert.assertNotNull(loadedReminder);
+		Assert.assertEquals(savedReminder, loadedReminder);
+		Assert.assertEquals(entry, loadedReminder.getEntry());
+		Assert.assertEquals("Reminder - 4", loadedReminder.getDescription());
+		Assert.assertEquals("Hello world", loadedReminder.getEmailBody());
+	}
+	
+	@Test
+	public void markAsSend() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-5");
+		Identity recepient = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-5");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 5);
+		Assert.assertNotNull(savedReminder);
+		dbInstance.commitAndCloseSession();
+		
+		SentReminderImpl sentReminder = reminderDao.markAsSend(savedReminder, recepient, "ok");
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(sentReminder);
+		Assert.assertNotNull(sentReminder.getKey());
+		Assert.assertEquals("ok", sentReminder.getStatus());
+		Assert.assertEquals(savedReminder, sentReminder.getReminder());
+		Assert.assertEquals(recepient, sentReminder.getIdentity());
+	}
+	
+	@Test
+	public void getReminderInfos() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-6");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-6a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-6b");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 6);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(savedReminder);
+		
+		//send 2 reminders
+		SentReminderImpl sentReminder1 = reminderDao.markAsSend(savedReminder, recepient1, "ok");
+		SentReminderImpl sentReminder2 = reminderDao.markAsSend(savedReminder, recepient2, "error");
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(sentReminder1);
+		Assert.assertNotNull(sentReminder2);
+		
+		//check reminder infos
+		List<ReminderInfos> reminderInfos = reminderDao.getReminderInfos(entry);
+		Assert.assertNotNull(reminderInfos);
+		Assert.assertEquals(1, reminderInfos.size());
+		ReminderInfos reminderInfo = reminderInfos.get(0);
+		Assert.assertNotNull(reminderInfo);
+		
+		Assert.assertEquals(savedReminder.getKey(), reminderInfo.getKey());
+		Assert.assertEquals(2, reminderInfo.getNumOfRemindersSent());
+		Assert.assertEquals(creator.getKey(), reminderInfo.getCreatorKey());
+		Assert.assertEquals("Reminder - 6", reminderInfo.getDescription());
+	}
+	
+	@Test
+	public void getSendReminders_byReminder() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-7");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-7a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-7b");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 7);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(savedReminder);
+		
+		//send 3 reminders
+		SentReminderImpl sentReminder1 = reminderDao.markAsSend(savedReminder, recepient1, "ok");
+		SentReminderImpl sentReminder2 = reminderDao.markAsSend(savedReminder, recepient2, "error");
+		SentReminderImpl sentReminder3 = reminderDao.markAsSend(savedReminder, recepient1, "error");
+		dbInstance.commitAndCloseSession();
+		
+		//load the sent reminder log
+		List<SentReminder> sentReminders = reminderDao.getSendReminders(savedReminder);
+		Assert.assertNotNull(sentReminders);
+		Assert.assertEquals(3, sentReminders.size());
+		Assert.assertTrue(sentReminders.contains(sentReminder1));
+		Assert.assertTrue(sentReminders.contains(sentReminder2));
+		Assert.assertTrue(sentReminders.contains(sentReminder3));
+	}
+	
+	@Test
+	public void getSendReminders_byRepositoryEntry() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-8");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-8a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-8b");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 8);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(savedReminder);
+		
+		//send 3 reminders
+		SentReminderImpl sentReminder1 = reminderDao.markAsSend(savedReminder, recepient1, "ok");
+		SentReminderImpl sentReminder2 = reminderDao.markAsSend(savedReminder, recepient2, "error");
+		SentReminderImpl sentReminder3 = reminderDao.markAsSend(savedReminder, recepient2, "error");
+		dbInstance.commitAndCloseSession();
+		
+		//load the sent reminder log
+		List<SentReminder> sentReminders = reminderDao.getSendReminders(entry);
+		Assert.assertNotNull(sentReminders);
+		Assert.assertEquals(3, sentReminders.size());
+		Assert.assertTrue(sentReminders.contains(sentReminder1));
+		Assert.assertTrue(sentReminders.contains(sentReminder2));
+		Assert.assertTrue(sentReminders.contains(sentReminder3));
+	}
+	
+	@Test
+	public void getReminderRecipientKeys() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-9");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9b");
+		Identity recepient3 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9c");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder savedReminder = createAndSaveReminder(entry, creator, 8);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(savedReminder);
+		
+		//send 3 reminders
+		reminderDao.markAsSend(savedReminder, recepient1, "ok");
+		reminderDao.markAsSend(savedReminder, recepient2, "error");
+		reminderDao.markAsSend(savedReminder, recepient3, "error");
+		dbInstance.commitAndCloseSession();
+		
+		//load the sent reminder log
+		List<Long> recipientKeys = reminderDao.getReminderRecipientKeys(savedReminder);
+		Assert.assertNotNull(recipientKeys);
+		Assert.assertEquals(3, recipientKeys.size());
+		Assert.assertTrue(recipientKeys.contains(recepient1.getKey()));
+		Assert.assertTrue(recipientKeys.contains(recepient2.getKey()));
+		Assert.assertTrue(recipientKeys.contains(recepient3.getKey()));
+	}
+	
+	@Test
+	public void deleteReminder() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-9");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9b");
+		Identity recepient3 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-9c");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder reminderToDelete = createAndSaveReminder(entry, creator, 8);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(reminderToDelete);
+		
+		//send 4 reminders
+		reminderDao.markAsSend(reminderToDelete, recepient1, "ok");
+		reminderDao.markAsSend(reminderToDelete, recepient2, "error");
+		reminderDao.markAsSend(reminderToDelete, recepient3, "error");
+		reminderDao.markAsSend(reminderToDelete, recepient2, "error");
+		dbInstance.commitAndCloseSession();
+		
+		//check
+		List<SentReminder> sentReminders = reminderDao.getSendReminders(reminderToDelete);
+		Assert.assertNotNull(sentReminders);
+		Assert.assertEquals(4, sentReminders.size());
+		
+		reminderDao.delete(reminderToDelete);
+		dbInstance.commit();
+		
+		//check that the reminder is missing
+		List<Reminder> deletedReminders = reminderDao.getReminders(entry);
+		Assert.assertNotNull(deletedReminders);
+		Assert.assertEquals(0, deletedReminders.size());
+	}
+	
+	/**
+	 * Check that not all reminders are deleted from the database.
+	 */
+	@Test
+	public void deleteReminder_paranoia() {
+		//create and reminder and an identity
+		Identity creator = JunitTestHelper.createAndPersistIdentityAsRndUser("creator-rem-10");
+		Identity recepient1 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-10a");
+		Identity recepient2 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-10b");
+		Identity recepient3 = JunitTestHelper.createAndPersistIdentityAsRndUser("recepient-rem-10c");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		Reminder reminderToDelete = createAndSaveReminder(entry, creator, 10);
+		Reminder survivingReminder = createAndSaveReminder(entry, creator, 10);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(reminderToDelete);
+		
+		//send 4 reminders
+		reminderDao.markAsSend(reminderToDelete, recepient1, "ok");
+		reminderDao.markAsSend(reminderToDelete, recepient2, "error");
+		SentReminder sentReminder1 = reminderDao.markAsSend(survivingReminder, recepient3, "error");
+		SentReminder sentReminder2 = reminderDao.markAsSend(survivingReminder, recepient2, "error");
+		dbInstance.commitAndCloseSession();
+		
+		//check
+		List<SentReminder> sentRemindersToDelete = reminderDao.getSendReminders(reminderToDelete);
+		Assert.assertNotNull(sentRemindersToDelete);
+		Assert.assertEquals(2, sentRemindersToDelete.size());
+		List<SentReminder> survivingSentReminders = reminderDao.getSendReminders(survivingReminder);
+		Assert.assertNotNull(survivingSentReminders);
+		Assert.assertEquals(2, survivingSentReminders.size());
+		
+		reminderDao.delete(reminderToDelete);
+		dbInstance.commit();
+		
+		//check that the reminder is missing
+		List<Reminder> deletedReminders = reminderDao.getReminders(entry);
+		Assert.assertNotNull(deletedReminders);
+		Assert.assertEquals(1, deletedReminders.size());
+		Assert.assertEquals(survivingReminder, deletedReminders.get(0));
+		//check that the send reminders are deleted but not all
+		List<SentReminder> reloadedSurvivingSentReminders = reminderDao.getSendReminders(survivingReminder);
+		Assert.assertNotNull(reloadedSurvivingSentReminders);
+		Assert.assertEquals(2, reloadedSurvivingSentReminders.size());
+		List<SentReminder> allSurvivingSentReminders = reminderDao.getSendReminders(entry);
+		Assert.assertNotNull(allSurvivingSentReminders);
+		Assert.assertEquals(2, allSurvivingSentReminders.size());
+		Assert.assertTrue(allSurvivingSentReminders.contains(sentReminder1));
+		Assert.assertTrue(allSurvivingSentReminders.contains(sentReminder2));
+	}
+	
+	private Reminder createAndSaveReminder(RepositoryEntry entry, Identity creator, int num) {
+		Reminder reminder = reminderDao.createReminder(entry, creator);
+		reminder.setConfiguration("<rules></rules>");
+		reminder.setDescription("Reminder - " + num);
+		reminder.setEmailBody("Hello world - " + num);
+		return reminderDao.save(reminder);
+	}
+	
+	@Test
+	public void getCourseEnrollmentDates() {
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("coach-rem-11");
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("participant-rem-11a");
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("participant-rem-11b");
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("participant-rem-11c");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		repositoryEntryRelationDao.addRole(coach, entry, GroupRoles.coach.name());
+		repositoryEntryRelationDao.addRole(participant1, entry, GroupRoles.participant.name());
+		repositoryEntryRelationDao.addRole(participant2, entry, GroupRoles.participant.name());
+		repositoryEntryRelationDao.addRole(participant3, entry, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		List<Identity> identities = new ArrayList<>();
+		identities.add(coach);
+		identities.add(participant1);
+		identities.add(participant2);
+		identities.add(participant3);
+		
+		//get the dates
+		Map<Long,Date> enrollmentDates = reminderDao.getCourseEnrollmentDates(entry, identities);
+		Assert.assertNotNull(enrollmentDates);
+		Assert.assertEquals(4, enrollmentDates.size());
+		Assert.assertTrue(enrollmentDates.containsKey(coach.getKey()));
+		Assert.assertTrue(enrollmentDates.containsKey(participant1.getKey()));
+		Assert.assertTrue(enrollmentDates.containsKey(participant2.getKey()));
+		Assert.assertTrue(enrollmentDates.containsKey(participant3.getKey()));
+		Assert.assertNotNull(enrollmentDates.get(coach.getKey()));
+		Assert.assertNotNull(enrollmentDates.get(participant1.getKey()));
+		Assert.assertNotNull(enrollmentDates.get(participant2.getKey()));
+		Assert.assertNotNull(enrollmentDates.get(participant3.getKey()));
+	}
 }