diff --git a/src/main/java/org/olat/core/gui/components/progressbar/ProgressBarRenderer.java b/src/main/java/org/olat/core/gui/components/progressbar/ProgressBarRenderer.java
index c2814ae3b01ef8dd6ddd1ba9c85ad608637c02b3..cb4a35944c9bd01862e2eb3f37541e30f6181120 100644
--- a/src/main/java/org/olat/core/gui/components/progressbar/ProgressBarRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/progressbar/ProgressBarRenderer.java
@@ -69,7 +69,7 @@ public class ProgressBarRenderer extends DefaultComponentRenderer {
 			.append("%", "px", ubar.isWidthInPercent())
 			.append(";\"><div class='progress-bar' style=\"width:")
 			.append(Math.round(percent * ubar.getWidth() / 100))
-			.append("px\" title=\"")
+			.append("%", "px", ubar.isWidthInPercent()).append("\" title=\"")
 			.append(Math.round(percent))
 			.append("%\">");
 		if (renderLabels) {
diff --git a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbPanel.java b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbPanel.java
index b39e624031f7077fe0bcb031913f3dd940b19aa6..f256b6914fc20eadf55a0242db06068924de2a0b 100644
--- a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbPanel.java
+++ b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbPanel.java
@@ -29,6 +29,8 @@ import org.olat.core.gui.control.Controller;
  */
 public interface BreadcrumbPanel extends StackedPanel {
 	
+	public int size();
+	
 	/**
 	 * Dismiss all controller and replace the root
 	 * @param displayName
diff --git a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java
index 5d85bdf4363a96099fc10b66e178db4bad90ccbe..9b7a4e0aa6ae5d7bb3381611020ae3e3622589c0 100644
--- a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java
+++ b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java
@@ -201,6 +201,11 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Bre
 		BusinessControlFactory.getInstance().addToHistory(ureq, wControl);
 	}
 	
+	public int size() {
+		return stack == null ? 0 : stack.size();
+	}
+	
+	@Override
 	public Controller getRootController() {
 		Controller controller = null;
 		if(stack.size() > 0) {
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
index 90d8e34cb477988d7f005e3fe5d96a6e0a26a28a..fb0aae73a9a616b0e84bfbec14682eca257b92e1 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
@@ -110,6 +110,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 	private final AssessmentToolContainer toolContainer;
 	private IdentityListCourseNodeTableModel usersTableModel;
 	
+	private List<Controller> toolsCtrl;
 	private AssessedIdentityController currentIdentityCtrl;
 	
 	@Autowired
@@ -289,6 +290,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 			AssessableCourseNode acn = (AssessableCourseNode)courseNode;
 			ICourse course = CourseFactory.loadCourse(courseEntry);
 			AssessmentToolOptions options = new AssessmentToolOptions();
+			options.setAdmin(assessmentCallback.isAdmin());
 			if(group == null) {
 				options.setIdentities(assessedIdentities);
 				fillAlternativeToAssessableIdentityList(options);
@@ -310,7 +312,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 					}
 				}
 			}
-			
+			toolsCtrl = tools;
 		}
 		flc.contextPut("toolCmpNames", toolCmpNames);
 	}
@@ -414,6 +416,10 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 			} else if(event == Event.CANCELLED_EVENT) {
 				stackPanel.popController(currentIdentityCtrl);
 			}
+		} else if(toolsCtrl != null && toolsCtrl.contains(source)) {
+			if(event == Event.CHANGED_EVENT) {
+				updateModel(ureq, null, null, null);
+			}
 		}
 		super.event(ureq, source, event);
 	}
diff --git a/src/main/java/org/olat/course/nodes/AssessmentToolOptions.java b/src/main/java/org/olat/course/nodes/AssessmentToolOptions.java
index 6010ed80def0d64cca7e65061b4dd749fcf5ea37..da31805994e51151ae7352a35541adbbb2980af3 100644
--- a/src/main/java/org/olat/course/nodes/AssessmentToolOptions.java
+++ b/src/main/java/org/olat/course/nodes/AssessmentToolOptions.java
@@ -33,10 +33,23 @@ import org.olat.group.BusinessGroup;
  */
 public class AssessmentToolOptions {
 	
+	private boolean admin;
 	private BusinessGroup group;
 	private List<Identity> identities;
 	private AlternativeToIdentities alternativeToIdentities;
 	
+	public AssessmentToolOptions() {
+		//
+	}
+	
+	public boolean isAdmin() {
+		return admin;
+	}
+
+	public void setAdmin(boolean admin) {
+		this.admin = admin;
+	}
+
 	public BusinessGroup getGroup() {
 		return group;
 	}
diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
index f19f4aa1ff0eff1b609959157496bcfcfd176f22..2d3677c91341baa244c9940309a3416b9b1b0974 100644
--- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
@@ -85,8 +85,10 @@ import org.olat.ims.qti.statistics.QTIStatisticSearchParams;
 import org.olat.ims.qti.statistics.QTIType;
 import org.olat.ims.qti.statistics.ui.QTI12PullTestsToolController;
 import org.olat.ims.qti.statistics.ui.QTI12StatisticsToolController;
+import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat;
 import org.olat.ims.qti21.model.QTI21StatisticSearchParams;
 import org.olat.ims.qti21.ui.QTI21AssessmentDetailsController;
+import org.olat.ims.qti21.ui.QTI21ResetToolController;
 import org.olat.ims.qti21.ui.statistics.QTI21StatisticResourceResult;
 import org.olat.ims.qti21.ui.statistics.QTI21StatisticsToolController;
 import org.olat.modules.ModuleConfiguration;
@@ -205,12 +207,14 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
 		RepositoryEntry qtiTestEntry = getReferencedRepositoryEntry();
 		if(ImsQTI21Resource.TYPE_NAME.equals(qtiTestEntry.getOlatResource().getResourceableTypeName())) {
 			tools.add(new QTI21StatisticsToolController(ureq, wControl, stackPanel, courseEnv, options, this));
-			//TODO qti implements the pull tests
+			if(options.isAdmin()) {
+				tools.add(new QTI21ResetToolController(ureq, wControl, courseEnv, options, this));
+			}
 		} else {
 			tools.add(new QTI12StatisticsToolController(ureq, wControl, stackPanel, courseEnv, options, this));
 			if(options.getGroup() == null && options.getIdentities() != null && options.getIdentities().size() > 0) {
 				for(Identity assessedIdentity:options.getIdentities()) {
-					if(isTestRunning(assessedIdentity, courseEnv)) {
+					if(isQTI12TestRunning(assessedIdentity, courseEnv)) {
 						tools.add(new QTI12PullTestsToolController(ureq, wControl, courseEnv, options, this));
 						break;
 					}
@@ -220,7 +224,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
 		return tools;
 	}
 	
-	public boolean isTestRunning(Identity assessedIdentity, CourseEnvironment courseEnv) {
+	public boolean isQTI12TestRunning(Identity assessedIdentity, CourseEnvironment courseEnv) {
 		String resourcePath = courseEnv.getCourseResourceableId() + File.separator + getIdent();
 		FilePersister qtiPersister = new FilePersister(assessedIdentity, resourcePath);
 		return qtiPersister.exists();
@@ -585,6 +589,11 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
 					OnyxExportManager.getInstance().exportResults(results, exportStream, this);
 				}
 				return true;
+			} else if(ImsQTI21Resource.TYPE_NAME.equals(re.getOlatResource().getResourceableTypeName())) {
+				QTI21ArchiveFormat qaf = new QTI21ArchiveFormat(locale);
+				RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+				qaf.export(courseEntry, getIdent(), re, exportStream);
+				return true;	
 			} else {
 				String shortTitle = getShortTitle();
 				QTIExportManager qem = QTIExportManager.getInstance();
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index af3e3eb22d0f358985b8c5b23d2d490ea2f1a7d2..1bf752c27317b12dd7c34c47c97e7a156c3f853d 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -390,6 +390,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			initTools(toolsDropdown, course, uce);
 			initSettingsTools(settingsDropdown);
 			initEditionTools(settingsDropdown);
+			initDeleteTools(settingsDropdown, true);
 		}
 		initToolsMyCourse(course, uce);
 		initGeneralTools(course);
@@ -546,7 +547,40 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			}
 		}
 	}
-	
+
+	@Override
+	protected void initDeleteTools(Dropdown settingsDropdown, boolean needSpacer) {
+		RepositoryEntry re = getRepositoryEntry();
+		boolean closeManged = RepositoryEntryManagedFlag.isManaged(re, RepositoryEntryManagedFlag.close);
+		
+		if(reSecurity.isEntryAdmin()) {
+			boolean deleteManaged = RepositoryEntryManagedFlag.isManaged(re, RepositoryEntryManagedFlag.delete);
+			if(settingsDropdown.size() > 0 && !deleteManaged) {
+				settingsDropdown.addComponent(new Spacer("close-delete"));
+			}
+
+			if(!closeManged || !deleteManaged) {
+				// If a resource is closable (currently only course) and
+				// deletable (currently all resources) we offer those two
+				// actions in a separate page, unless both are managed
+				// operations. In that case we don't show anything at all.				
+				// If only one of the two actions are managed, we go to the
+				// separate page as well and show only the relevant action
+				// there.
+				lifeCycleChangeLink = LinkFactory.createToolLink("lifeCycleChange", translate("details.lifecycle.change"), this, "o_icon o_icon-fw o_icon_lifecycle");
+				settingsDropdown.addComponent(lifeCycleChangeLink);
+			} else {				
+				if(!deleteManaged) {
+					String type = translate(handler.getSupportedType());
+					String deleteTitle = translate("details.delete.alt", new String[]{ type });
+					deleteLink = LinkFactory.createToolLink("delete", deleteTitle, this, "o_icon o_icon-fw o_icon_delete_item");
+					deleteLink.setElementCssClass("o_sel_repo_close");
+					settingsDropdown.addComponent(deleteLink);
+				}
+			}
+		}
+	}
+
 	private void initToolsMyCourse(ICourse course, UserCourseEnvironmentImpl uce) {
 		boolean assessmentLock = isAssessmentLock();
 
diff --git a/src/main/java/org/olat/course/statistic/StatisticResourceNode.java b/src/main/java/org/olat/course/statistic/StatisticResourceNode.java
index 05d2dcfe405c797876d57f4015fb4af4d66a4d41..b146d4c87b54e3f14dccf3b2cf7a2fac2527c309 100644
--- a/src/main/java/org/olat/course/statistic/StatisticResourceNode.java
+++ b/src/main/java/org/olat/course/statistic/StatisticResourceNode.java
@@ -29,7 +29,7 @@ import org.olat.course.nodes.CourseNodeFactory;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class StatisticResourceNode  extends GenericTreeNode {
+public class StatisticResourceNode extends GenericTreeNode {
 	private static final long serialVersionUID = -1528483744004133623L;
 	private final CourseNode courseNode;
 	private final StatisticResourceResult result;
diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
index 9f3aecb86e7cf73d2a00b05ba597770c3f7d4fe6..730fdd97d839c7805e3f64365f443f8c42b509fe 100644
--- a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
+++ b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
@@ -127,7 +127,7 @@ public class QTI12PullTestsToolController extends BasicController implements Act
 		int count = 0;
 		StringBuilder fullnames = new StringBuilder(256);
 		for(Identity assessedIdentity:assessedIdentities) {
-			if(courseNode.isTestRunning(assessedIdentity, courseEnv)) {
+			if(courseNode.isQTI12TestRunning(assessedIdentity, courseEnv)) {
 				if(fullnames.length() > 0) fullnames.append(", ");
 				String name = userManager.getUserDisplayName(assessedIdentity);
 				if(StringHelper.containsNonWhitespace(name)) {
@@ -153,7 +153,7 @@ public class QTI12PullTestsToolController extends BasicController implements Act
 	private void doRetrieveTests() {
 		ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId());
 		for(Identity assessedIdentity:assessedIdentities) {
-			if(courseNode.isTestRunning(assessedIdentity, courseEnv)) {
+			if(courseNode.isQTI12TestRunning(assessedIdentity, courseEnv)) {
 				IQRetrievedEvent retrieveEvent = new IQRetrievedEvent(assessedIdentity, courseEnv.getCourseResourceableId(), courseNode.getIdent());
 				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(retrieveEvent, retrieveEvent);
 				retrieveTest(assessedIdentity, course);
diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java
index 4e0c9408e0c9fa19269dba2ba6f99b74c6a604cb..f349049e6821e4d715c02786a9fe441a9875c48b 100644
--- a/src/main/java/org/olat/ims/qti21/QTI21Service.java
+++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java
@@ -114,6 +114,16 @@ public interface QTI21Service {
 	 */
 	public boolean needManualCorrection(ResolvedAssessmentTest resolvedAssessmentTest);
 	
+	/**
+	 * 
+	 * @param identities
+	 * @param testEntry
+	 * @param entry
+	 * @param subIdent
+	 * @return
+	 */
+	public boolean deleteAssessmentTestSession(List<Identity> identities, RepositoryEntryRef testEntry, RepositoryEntryRef entry, String subIdent);
+	
 	/**
 	 * Remove all test sessions in author mode, e.g. after an assessment test
 	 * was changed.
diff --git a/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java b/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java
index f590118df1126753f59e8b15464e52933fc00cc6..3054016fbdbaec43061a7d7d10a33dab0888f949 100644
--- a/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java
+++ b/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java
@@ -23,7 +23,10 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 
+import javax.persistence.TypedQuery;
+
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.util.StringHelper;
 import org.olat.ims.qti21.AssessmentItemSession;
 import org.olat.ims.qti21.AssessmentResponse;
 import org.olat.ims.qti21.AssessmentTestSession;
@@ -120,20 +123,27 @@ public class AssessmentResponseDAO {
 		  .append(" inner join fetch testSession.assessmentEntry assessmentEntry")
 		  .append(" inner join assessmentEntry.identity as ident")
 		  .append(" inner join ident.user as usr")
-		  .append(" where testSession.repositoryEntry.key=:repoEntryKey")
-		  .append("  and testSession.testEntry.key=:testEntryKey")
-		  .append("  and testSession.subIdent=:subIdent")
+		  .append(" where testSession.testEntry.key=:testEntryKey")
 		  .append("  and testSession.terminationTime is not null");
+		if(courseEntry != null) {
+			sb.append(" and testSession.repositoryEntry.key=:repoEntryKey");
+		}
+		if(StringHelper.containsNonWhitespace(subIdent)) {
+			sb.append(" and testSession.subIdent=:subIdent");
+		}
 
 		//need to be anonymized
 		sb.append(" order by usr.lastName, testSession.key, itemSession.key");
 		
-		return dbInstance.getCurrentEntityManager()
+		TypedQuery<AssessmentResponse> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), AssessmentResponse.class)
-				.setParameter("repoEntryKey", courseEntry.getKey())
-				.setParameter("testEntryKey", testEntry.getKey())
-				.setParameter("subIdent", subIdent)
-				.getResultList();
+				.setParameter("testEntryKey", testEntry.getKey());
+		if(courseEntry != null) {
+			query.setParameter("repoEntryKey", courseEntry.getKey());
+		}
+		if(StringHelper.containsNonWhitespace(subIdent)) {
+			query.setParameter("subIdent", subIdent);
+		}
+		return query.getResultList();
 	}
-
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
index 1340cfbaaac4d006885824dbb37a6002ba1bb6ed..1d739d2d460fcccc0dd09a068539c5f8c9577d56 100644
--- a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
+++ b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
@@ -117,6 +117,39 @@ public class AssessmentTestSessionDAO {
 		return lastSessions == null || lastSessions.isEmpty() ? null : lastSessions.get(0);
 	}
 	
+	public List<AssessmentTestSession> getTestSessions(RepositoryEntryRef testEntry,
+			RepositoryEntryRef entry, String subIdent, IdentityRef identity) {
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select session from qtiassessmenttestsession session")
+		  .append(" left join fetch session.assessmentEntry asEntry")
+		  .append(" where session.testEntry.key=:testEntryKey and session.identity.key=:identityKey");
+		if(entry != null) {
+			sb.append(" and session.repositoryEntry.key=:courseEntryKey");
+		} else {
+			sb.append(" and session.repositoryEntry.key is null");
+		}
+		
+		if(subIdent != null) {
+			sb.append(" and session.subIdent=:courseSubIdent");
+		} else {
+			sb.append(" and session.subIdent is null");
+		}
+		
+		TypedQuery<AssessmentTestSession> query = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), AssessmentTestSession.class)
+				.setParameter("testEntryKey", testEntry.getKey())
+				.setParameter("identityKey", identity.getKey());
+		if(entry != null) {
+			query.setParameter("courseEntryKey", entry.getKey());
+		}
+		if(subIdent != null) {
+			query.setParameter("courseSubIdent", subIdent);
+		}
+		
+		return query.getResultList();
+	}
+	
 	/**
 	 * Create a folder for a session in bcroot.
 	 * 
diff --git a/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java b/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java
index 1c8fead8fa1ed35a3067b2082066fbad805bef75..e2715fba17faeb7f16bf44fb8476ce4106c6c862 100644
--- a/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java
+++ b/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java
@@ -24,19 +24,26 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.DoubleAdder;
 
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
+import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder;
+import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.AbstractEntry;
+import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.NumericalEntry;
+import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.TextEntry;
 
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.CorrectResponse;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.ChoiceInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
-import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.MapEntry;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.TextEntryInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.shared.FieldValue;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
+import uk.ac.ed.ph.jqtiplus.value.BaseType;
 import uk.ac.ed.ph.jqtiplus.value.Cardinality;
 import uk.ac.ed.ph.jqtiplus.value.DirectedPairValue;
 import uk.ac.ed.ph.jqtiplus.value.IdentifierValue;
@@ -46,7 +53,6 @@ import uk.ac.ed.ph.jqtiplus.value.OrderedValue;
 import uk.ac.ed.ph.jqtiplus.value.PairValue;
 import uk.ac.ed.ph.jqtiplus.value.PointValue;
 import uk.ac.ed.ph.jqtiplus.value.SingleValue;
-import uk.ac.ed.ph.jqtiplus.value.StringValue;
 import uk.ac.ed.ph.jqtiplus.value.Value;
 
 /**
@@ -323,53 +329,17 @@ public class CorrectResponsesUtil {
 		return correctAnswers;
 	}
 	
-	public static final TextEntry getCorrectTextResponses(AssessmentItem assessmentItem, Interaction interaction) {
+	public static final AbstractEntry getCorrectTextResponses(AssessmentItem assessmentItem, TextEntryInteraction interaction) {
 		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
-		
-		boolean caseSensitive = true;
-		List<String> alternatives = new ArrayList<>();
-		List<MapEntry> mapEntries = responseDeclaration.getMapping().getMapEntries();
-		for(MapEntry mapEntry:mapEntries) {
-			SingleValue mapKey = mapEntry.getMapKey();
-			if(mapKey instanceof StringValue) {
-				String value = ((StringValue)mapKey).stringValue();
-				alternatives.add(value);
-			}
-			
-			caseSensitive &= mapEntry.getCaseSensitive();
-		}
-		return new TextEntry(alternatives, caseSensitive);
-	}
-	
-	public static class TextEntry {
-		
-		private boolean caseSensitive;
-		private List<String> alternatives;
-		
-		public TextEntry(List<String> alternatives, boolean caseSensitive) {
-			this.alternatives = alternatives;
-			this.caseSensitive = caseSensitive;
-		}
-		
-		public boolean isCaseSensitive() {
-			return caseSensitive;
-		}
-
-		public List<String> getAlternatives() {
-			return alternatives;
-		}
-		
-		public boolean isCorrect(String response) {
-			for(String alternative:alternatives) {
-				if(caseSensitive) {
-					if(alternative.equals(response)) {
-						return true;
-					}
-				} else if(alternative.equalsIgnoreCase(response)) {
-					return true;
-				}
-			}
-			return false;
+		if(responseDeclaration.hasBaseType(BaseType.STRING) && responseDeclaration.hasCardinality(Cardinality.SINGLE)) {
+			TextEntry textEntry = new TextEntry(interaction);
+			FIBAssessmentItemBuilder.extractTextEntrySettingsFromResponseDeclaration(textEntry, responseDeclaration, new AtomicInteger(), new DoubleAdder());
+			return textEntry;
+		} else if(responseDeclaration.hasBaseType(BaseType.FLOAT) && responseDeclaration.hasCardinality(Cardinality.SINGLE)) {
+			NumericalEntry numericalEntry = new NumericalEntry(interaction);
+			FIBAssessmentItemBuilder.extractNumericalEntrySettings(assessmentItem, numericalEntry, responseDeclaration, new AtomicInteger(), new DoubleAdder());
+			return numericalEntry;
 		}
+		return null;
 	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index 22d604e17462027142775edd912905f8c233b6f7..860401d7a615595fc4a14701416b1f2768c4234f 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -32,9 +32,11 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -77,6 +79,7 @@ import org.olat.ims.qti21.model.audit.CandidateEvent;
 import org.olat.ims.qti21.model.audit.CandidateItemEventType;
 import org.olat.ims.qti21.model.audit.CandidateTestEventType;
 import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.manager.AssessmentEntryDAO;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
 import org.springframework.beans.factory.DisposableBean;
@@ -165,6 +168,8 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 	@Autowired
 	private AssessmentTestMarksDAO testMarksDao;
 	@Autowired
+	private AssessmentEntryDAO assessmentEntryDao;
+	@Autowired
 	private QTI21Module qtiModule;
 	@Autowired
 	private CoordinatorManager coordinatorManager;
@@ -397,6 +402,27 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 			}
 		});
 	}
+	
+	@Override
+	public boolean deleteAssessmentTestSession(List<Identity> identities, RepositoryEntryRef testEntry, RepositoryEntryRef entry, String subIdent) {
+		Set<AssessmentEntry> entries = new HashSet<>();
+		for(Identity identity:identities) {
+			List<AssessmentTestSession> sessions = testSessionDao.getTestSessions(testEntry, entry, subIdent, identity);
+			for(AssessmentTestSession session:sessions) {
+				if(session.getAssessmentEntry() != null) {
+					entries.add(session.getAssessmentEntry());
+				}
+				File fileStorage = testSessionDao.getSessionStorage(session);
+				testSessionDao.deleteTestSession(session);
+				FileUtils.deleteDirsAndFiles(fileStorage, true, true);
+			}
+		}
+		
+		for(AssessmentEntry assessmentEntry:entries) {
+			assessmentEntryDao.resetAssessmentEntry(assessmentEntry);
+		}
+		return true;
+	}
 
 	@Override
 	public boolean deleteAuthorAssessmentTestSession(RepositoryEntryRef testEntry) {
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java b/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java
index 467014b488f43247df334dfe5e24c97b9966165d..d1f5916e1c37525ee40c6156489fb2df6bf05f5f 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java
@@ -20,6 +20,7 @@
 package org.olat.ims.qti21.manager.archive;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -28,7 +29,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
+import org.apache.commons.io.IOUtils;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.translator.Translator;
@@ -40,6 +44,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.io.ShieldOutputStream;
 import org.olat.core.util.openxml.OpenXMLWorkbook;
 import org.olat.core.util.openxml.OpenXMLWorkbookResource;
 import org.olat.core.util.openxml.OpenXMLWorksheet;
@@ -59,7 +64,6 @@ import org.olat.ims.qti21.manager.QTI21ServiceImpl;
 import org.olat.ims.qti21.manager.archive.interactions.AssociateInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.ChoiceInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.DefaultInteractionArchive;
-import org.olat.ims.qti21.manager.archive.interactions.NoOutputInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.ExtendedTextInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.GapMatchInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.GraphicAssociateInteractionArchive;
@@ -71,6 +75,7 @@ import org.olat.ims.qti21.manager.archive.interactions.InlineChoiceInteractionAr
 import org.olat.ims.qti21.manager.archive.interactions.InteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.MatchInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.MediaInteractionArchive;
+import org.olat.ims.qti21.manager.archive.interactions.NoOutputInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.OrderInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.PositionObjectInteractionArchive;
 import org.olat.ims.qti21.manager.archive.interactions.SelectPointInteractionArchive;
@@ -173,9 +178,55 @@ public class QTI21ArchiveFormat {
 	public boolean hasResults(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) {
 		return responseDao.hasResponses(courseEntry, subIdent, testEntry);
 	}
+
+	public void export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry, ZipOutputStream exportStream) {
+		FileResourceManager frm = FileResourceManager.getInstance();
+		File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
+		resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false);
+		
+		CourseNode courseNode = CourseFactory.loadCourse(courseEntry).getRunStructure().getNode(subIdent);
+		String label = courseNode.getType() + "_"
+				+ StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName())
+				+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis()))
+				+ ".xlsx";
+		
+		export(courseEntry, subIdent, testEntry, label, exportStream);
+	}
 	
-	public MediaResource export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) {
+	public void export(RepositoryEntry testEntry, ZipOutputStream exportStream) {
+		FileResourceManager frm = FileResourceManager.getInstance();
+		File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
+		resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false);
 		
+		String archiveName = "qti21test_"
+				+ StringHelper.transformDisplayNameToFileSystemName(testEntry.getDisplayname())
+				+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + ".xlsx";
+		export(null, null, testEntry, archiveName, exportStream);
+	}
+	
+	private void export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry, String filename, ZipOutputStream exportStream) {
+		//content
+		final List<AssessmentResponse> responses = responseDao.getResponse(courseEntry, subIdent, testEntry);
+		try {
+			exportStream.putNextEntry(new ZipEntry(filename));
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(new ShieldOutputStream(exportStream), 1);
+			
+			//headers
+			OpenXMLWorksheet exportSheet = workbook.nextWorksheet();
+			exportSheet.setHeaderRows(2);
+			writeHeaders_1(exportSheet, workbook);
+			writeHeaders_2(exportSheet, workbook);
+			writeData(responses, exportSheet, workbook);
+			
+			IOUtils.closeQuietly(workbook);
+
+			exportStream.closeEntry();
+		} catch (IOException e) {
+			log.error("", e);
+		}
+	}
+	
+	public MediaResource export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) {
 		FileResourceManager frm = FileResourceManager.getInstance();
 		File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
 		resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false);
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/TextEntryInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/TextEntryInteractionArchive.java
index b602bae321fa7cea34bd7957fa32c760d9dc3225..cd6ed2ec305708fbb4bf6aa6846e60ad27a151d7 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/TextEntryInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/TextEntryInteractionArchive.java
@@ -24,7 +24,7 @@ import org.olat.core.util.openxml.OpenXMLWorkbook;
 import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
 import org.olat.ims.qti21.AssessmentResponse;
 import org.olat.ims.qti21.manager.CorrectResponsesUtil;
-import org.olat.ims.qti21.manager.CorrectResponsesUtil.TextEntry;
+import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.AbstractEntry;
 
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
@@ -52,10 +52,10 @@ public class TextEntryInteractionArchive extends DefaultInteractionArchive {
 		String stringuifiedResponses = response == null ? null : response.getStringuifiedResponse();
 		if(StringHelper.containsNonWhitespace(stringuifiedResponses)) {
 			TextEntryInteraction textEntryInteraction = (TextEntryInteraction)interaction;
-			TextEntry correctAnswers = CorrectResponsesUtil.getCorrectTextResponses(item, textEntryInteraction);
+			AbstractEntry correctAnswers = CorrectResponsesUtil.getCorrectTextResponses(item, textEntryInteraction);
 			stringuifiedResponses = CorrectResponsesUtil.stripResponse(stringuifiedResponses);
-			
-			boolean correct = correctAnswers.isCorrect(stringuifiedResponses);
+
+			boolean correct = correctAnswers.match(stringuifiedResponses);
 			if(correct) {
 				dataRow.addCell(col++, stringuifiedResponses, workbook.getStyles().getCorrectStyle());
 			} else {
diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
index def9642a2a42c875df9e8f7dc9896c40d5875fab..8d4b0400d2ed6b594dda6a727001467e6757e409 100644
--- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
+++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
@@ -854,6 +854,8 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder {
 		public void setScore(Double score) {
 			this.score = score;
 		}
+		
+		public abstract boolean match(String response);
 	}
 	
 	public static class NumericalEntry extends AbstractEntry {
@@ -903,6 +905,19 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder {
 		public void setToleranceMode(ToleranceMode toleranceMode) {
 			this.toleranceMode = toleranceMode;
 		}
+
+		@Override
+		public boolean match(String response) {
+			try {
+				double firstNumber = Double.parseDouble(response);
+				return toleranceMode.isEqual(firstNumber, solution,
+						lowerTolerance, upperTolerance,
+				        true, true);
+			} catch (Exception e) {
+				log.error("", e);
+				return false;
+			}
+		}
 	}
 	
 	public static class TextEntry extends AbstractEntry {
@@ -1001,6 +1016,37 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder {
 				}
 			}
 		}
+		
+		/**
+		 * Quick method to find if a string match the correct responses of
+		 * the text entry.
+		 * 
+		 * @param response
+		 * @return
+		 */
+		public boolean match(String response) {
+			if(match(response, solution)) {
+				return true;
+			}
+			
+			for(TextEntryAlternative textEntryAlternative:alternatives) {
+				if(match(response, textEntryAlternative.getAlternative())) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean match(String response, String alternative) {
+			if(caseSensitive) {
+				if(alternative.equals(response)) {
+					return true;
+				}
+			} else if(alternative.equalsIgnoreCase(response)) {
+				return true;
+			}
+			return false;
+		}
 	}
 	
 	public static class TextEntryAlternative {
diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java
index dbc9d39807925c2cb2b5258a1a5c0c1e5306e12a..b41d62c12bb72c6d979ceda6030a5b8b85a85f76 100644
--- a/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java
@@ -183,7 +183,7 @@ public class AssessmentResultController extends FormBasicController {
 		
 		Results r = new Results(false, type.getCssClass());
 		r.setTitle(node.getSectionPartTitle());
-		r.setSessionStatus(this.translate(""));
+		r.setSessionStatus("");//init
 		
 		ItemSessionState sessionState = testSessionState.getItemSessionStates().get(testPlanNodeKey);
 		if(sessionState != null) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
index 0b2812917eb65c0f1abf81ef8899d3aad5703e65..082d46615503ce370e4af744583fc458ddef253d 100644
--- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
@@ -1413,7 +1413,7 @@ public class AssessmentTestDisplayController extends BasicController implements
 				resultsVisible = true;
 			}
 			
-			if(testSessionController.findNextEnterableTestPart() == null) {
+			if(testSessionController.getTestSessionState().isEnded() || testSessionController.findNextEnterableTestPart() == null) {
 				closeTestButton.setI18nKey("assessment.test.close.test");
 			} else {
 				closeTestButton.setI18nKey("assessment.test.close.testpart");
diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e40416fecdd25764a227d1470eb15b9122e3bfb7
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java
@@ -0,0 +1,171 @@
+/**
+ * <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.ims.qti21.ui;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.zip.ZipOutputStream;
+
+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.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.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.id.IdentityEnvironment;
+import org.olat.core.id.Roles;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.nodes.ArchiveOptions;
+import org.olat.course.nodes.AssessmentToolOptions;
+import org.olat.course.nodes.IQTESTCourseNode;
+import org.olat.course.nodes.QTICourseNode;
+import org.olat.course.run.environment.CourseEnvironment;
+import org.olat.course.run.scoring.ScoreEvaluation;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.course.run.userview.UserCourseEnvironmentImpl;
+import org.olat.group.BusinessGroupService;
+import org.olat.ims.qti21.QTI21Service;
+import org.olat.repository.RepositoryEntry;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 08.08.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class QTI21ResetToolController extends BasicController {
+	
+	private final Roles studentRoles = new Roles(false, false, false, false, false, false, false, false);
+	private final Link resetButton;
+	
+	private DialogBoxController confirmResetDialog;
+	
+	private final QTICourseNode courseNode;
+	private final CourseEnvironment courseEnv;
+	private final AssessmentToolOptions asOptions;
+	
+	@Autowired
+	private QTI21Service qtiService;
+	@Autowired
+	private BusinessGroupService businessGroupService;
+
+	public QTI21ResetToolController(UserRequest ureq, WindowControl wControl, 
+			CourseEnvironment courseEnv, AssessmentToolOptions asOptions, QTICourseNode courseNode) {
+		super(ureq, wControl);
+		this.courseNode = courseNode;
+		this.courseEnv = courseEnv;
+		this.asOptions = asOptions;
+		
+		resetButton = LinkFactory.createButton("reset.test.data.title", null, this);
+		resetButton.setTranslator(getTranslator());
+		putInitialPanel(resetButton);
+		getInitialComponent().setSpanAsDomReplaceable(true); // override to wrap panel as span to not break link layout 
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(resetButton == source) {
+			doConfirmReset(ureq);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(confirmResetDialog == source) {
+			if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) {
+				doReset(ureq);
+			}
+		}
+		super.event(ureq, source, event);
+	}
+
+	private void doConfirmReset(UserRequest ureq) {
+		String title = translate("reset.test.data.title");
+		String text = translate("reset.test.data.text");
+		confirmResetDialog = activateOkCancelDialog(ureq, title, text, confirmResetDialog);
+	}
+	
+	private void doReset(UserRequest ureq) {
+		List<Identity> identities;
+
+		ArchiveOptions options = new ArchiveOptions();
+		if(asOptions.getGroup() == null) {
+			identities = asOptions.getIdentities();
+			options.setIdentities(identities);
+		} else {
+			identities = businessGroupService.getMembers(asOptions.getGroup());
+			options.setGroup(asOptions.getGroup());
+		}
+
+		RepositoryEntry testEntry = courseNode.getReferencedRepositoryEntry();
+		RepositoryEntry courseEntry = courseEnv.getCourseGroupManager().getCourseEntry();
+
+		if(courseNode instanceof IQTESTCourseNode) {
+			IQTESTCourseNode testCourseNode = (IQTESTCourseNode)courseNode;
+			
+			ICourse course = CourseFactory.loadCourse(courseEntry);
+			archiveData(course, options);
+			
+			qtiService.deleteAssessmentTestSession(identities, testEntry, courseEntry, courseNode.getIdent());
+			for(Identity identity:identities) {
+				ScoreEvaluation scoreEval = new ScoreEvaluation(null, null);
+				
+				IdentityEnvironment ienv = new IdentityEnvironment(identity, studentRoles);
+				UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, courseEnv);
+				testCourseNode.updateUserScoreEvaluation(scoreEval, uce, getIdentity(), false);
+			}
+		}
+		
+		fireEvent(ureq, Event.CHANGED_EVENT);
+	}
+	
+	private void archiveData(ICourse course, ArchiveOptions options) {
+		File exportDirectory = CourseFactory.getOrCreateDataExportDirectory(getIdentity(), course.getCourseTitle());
+		String archiveName = courseNode.getType() + "_"
+				+ StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName())
+				+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + ".zip";
+
+		File exportFile = new File(exportDirectory, archiveName);
+		try(FileOutputStream fileStream = new FileOutputStream(exportFile);
+			ZipOutputStream exportStream = new ZipOutputStream(fileStream)) {
+			
+			courseNode.archiveNodeData(getLocale(), course, options, exportStream, "UTF-8");
+		} catch (IOException e) {
+			logError("", e);
+		}
+	}
+}
diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java
index b96bf821f0d4840447ca158c6d2f213a6c0cf846..e79d3b1feb64dccddd92e911e750131ab814a049 100644
--- a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java
@@ -20,7 +20,15 @@
 package org.olat.ims.qti21.ui;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Date;
+import java.util.List;
+import java.util.zip.ZipOutputStream;
 
+import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.dropdown.Dropdown;
@@ -32,15 +40,21 @@ 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.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.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.course.nodes.AssessmentToolOptions;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.ims.qti21.QTI21Constants;
 import org.olat.ims.qti21.QTI21Service;
+import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat;
 import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
 import org.olat.ims.qti21.ui.editor.AssessmentTestComposerController;
-import org.olat.ims.qti21.ui.statistics.QTI21AssessmentTestStatisticsController;
 import org.olat.modules.assessment.ui.AssessableResource;
 import org.olat.modules.assessment.ui.AssessmentToolController;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
@@ -62,11 +76,14 @@ import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest;
  */
 public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 	
-	private Link assessmentLink, testStatisticLink, qtiOptionsLink;
+	private Link assessmentLink, testStatisticLink, qtiOptionsLink, resetDataLink;
 	
+	private DialogBoxController confirmResetDialog;
 	private QTI21DeliveryOptionsController optionsCtrl;
 	private AssessmentToolController assessmentToolCtrl;
-	private QTI21AssessmentTestStatisticsController statsToolCtr;
+	private QTI21RuntimeStatisticsController statsToolCtr;
+	
+	private boolean reloadRuntime = false;
 
 	@Autowired
 	private QTI21Service qtiService;
@@ -75,19 +92,7 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 			RepositoryEntry re, RepositoryEntrySecurity reSecurity, RuntimeControllerCreator runtimeControllerCreator) {
 		super(ureq, wControl, re, reSecurity, runtimeControllerCreator);
 	}
-	
-	@Override
-	protected void initSettingsTools(Dropdown settingsDropdown) {
-		super.initSettingsTools(settingsDropdown);
-		if (reSecurity.isEntryAdmin()) {
-			settingsDropdown.addComponent(new Spacer(""));
 
-			qtiOptionsLink = LinkFactory.createToolLink("options", translate("tab.options"), this, "o_sel_repo_options");
-			qtiOptionsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_options");
-			settingsDropdown.addComponent(qtiOptionsLink);
-		}
-	}
-	
 	@Override
 	protected void initRuntimeTools(Dropdown toolsDropdown) {
 		if (reSecurity.isEntryAdmin()) {
@@ -120,6 +125,30 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 			toolsDropdown.addComponent(ordersLink);	
 		}
 	}
+	
+	@Override
+	protected void initSettingsTools(Dropdown settingsDropdown) {
+		super.initSettingsTools(settingsDropdown);
+		if (reSecurity.isEntryAdmin()) {
+			settingsDropdown.addComponent(new Spacer(""));
+
+			qtiOptionsLink = LinkFactory.createToolLink("options", translate("tab.options"), this, "o_sel_repo_options");
+			qtiOptionsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_options");
+			settingsDropdown.addComponent(qtiOptionsLink);
+		}
+	}
+	
+	@Override
+	protected void initDeleteTools(Dropdown settingsDropdown, boolean needSpacer) {
+		if (reSecurity.isEntryAdmin()) {
+			settingsDropdown.addComponent(new Spacer(""));
+
+			resetDataLink = LinkFactory.createToolLink("resetData", translate("tab.reset.data"), this, "o_sel_repo_reset_data");
+			resetDataLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item");
+			settingsDropdown.addComponent(resetDataLink);
+		}
+		super.initDeleteTools(settingsDropdown, !reSecurity.isEntryAdmin());
+	}
 
 	@Override
 	protected void event(UserRequest ureq, Component source, Event event) {
@@ -129,26 +158,40 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 			doAssessmentTool(ureq);
 		} else if(qtiOptionsLink == source) {
 			doQtiOptions(ureq);
+		} else if(resetDataLink == source) {
+			doConfirmResetData(ureq);
 		} else if(toolbarPanel == source) {
 			if(event instanceof PopEvent) {
 				PopEvent pe = (PopEvent)event;
 				Controller popedCtrl = pe.getController();
 				if(popedCtrl instanceof AssessmentTestComposerController) {
 					AssessmentTestComposerController composerCtrl = (AssessmentTestComposerController)popedCtrl;
-					if(composerCtrl.hasChanges()) {
+					if(composerCtrl.hasChanges() || reloadRuntime) {
 						doReloadRuntimeController(ureq);
 					}
 				} else if (popedCtrl instanceof QTI21DeliveryOptionsController) {
 					QTI21DeliveryOptionsController optCtrl = (QTI21DeliveryOptionsController)popedCtrl;
-					if(optCtrl.hasChanges()) {
+					if(optCtrl.hasChanges() || reloadRuntime) {
 						doReloadRuntimeController(ureq);
 					}
+				} else if(reloadRuntime) {
+					doReloadRuntimeController(ureq);
 				}
 			}
 		}
 		super.event(ureq, source, event);
 	}
 	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(confirmResetDialog == source) {
+			if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) {
+				doReset(ureq);
+			}
+		}
+		super.event(ureq, source, event);
+	}
+
 	private void doReloadRuntimeController(UserRequest ureq) {
 		disposeRuntimeController();
 		if(reSecurity.isEntryAdmin()) {
@@ -158,6 +201,7 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 		if(toolbarPanel.getTools().isEmpty()) {
 			initToolbar();
 		}
+		reloadRuntime = false;
 	}
 	
 	private Activateable2 doQtiOptions(UserRequest ureq) {
@@ -182,10 +226,15 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 		WindowControl swControl = addToHistory(ureq, ores, null);
 		
 		if (reSecurity.isEntryAdmin() || reSecurity.isCourseCoach() || reSecurity.isGroupCoach()) {
-			QTI21AssessmentTestStatisticsController ctrl = new QTI21AssessmentTestStatisticsController(ureq, swControl, getRepositoryEntry(), false);
+			AssessmentToolOptions asOptions = new AssessmentToolOptions();
+			QTI21RuntimeStatisticsController ctrl = new QTI21RuntimeStatisticsController(ureq, swControl,
+					getRepositoryEntry(), asOptions);
 			listenTo(ctrl);
-			statsToolCtr = pushController(ureq, "Statistics", ctrl);
-			currentToolCtr = statsToolCtr;
+			
+	
+	
+			statsToolCtr = pushController(ureq, translate("command.openteststatistic"), ctrl);
+			currentToolCtr = ctrl;
 			setActiveTool(testStatisticLink);
 			return statsToolCtr;
 		}
@@ -226,4 +275,41 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController  {
 		boolean hasPassed = assessmentTest.getOutcomeDeclaration(QTI21Constants.PASS_IDENTIFIER) != null;
 		return new AssessableResource(hasScore, hasPassed, true, true, minScore, maxScore, null);
 	}
-}
+	
+	private void doConfirmResetData(UserRequest ureq) {
+		String title = translate("reset.test.data.title");
+		String text = translate("reset.test.data.text");
+		confirmResetDialog = activateOkCancelDialog(ureq, title, text, confirmResetDialog);
+	}
+	
+	private void doReset(UserRequest ureq) {
+		RepositoryEntry testEntry = getRepositoryEntry();
+		List<Identity> identities = repositoryService.getMembers(testEntry);
+		
+		//backup
+		String archiveName = "qti21test_"
+				+ StringHelper.transformDisplayNameToFileSystemName(testEntry.getDisplayname())
+				+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + ".zip";
+		Path exportPath = Paths.get(FolderConfig.getCanonicalRoot(), FolderConfig.getUserHomes(), getIdentity().getName(),
+				"private", "archive", StringHelper.transformDisplayNameToFileSystemName(testEntry.getDisplayname()), archiveName);
+		File exportFile = exportPath.toFile();
+		exportFile.getParentFile().mkdirs();
+		
+		try(FileOutputStream fileStream = new FileOutputStream(exportFile);
+			ZipOutputStream exportStream = new ZipOutputStream(fileStream)) {
+			new QTI21ArchiveFormat(getLocale()).export(testEntry, exportStream);
+		} catch (IOException e) {
+			logError("", e);
+		}
+
+		//delete
+		qtiService.deleteAssessmentTestSession(identities, testEntry, null, null);
+		
+		//reload
+		if(toolbarPanel.size() == 1) {
+			doReloadRuntimeController(ureq);
+		} else {
+			reloadRuntime = true;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcfbb049a40fcde46ae3a379c852336c40309182
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java
@@ -0,0 +1,143 @@
+/**
+ * <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.ims.qti21.ui;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.basesecurity.Group;
+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.panel.Panel;
+import org.olat.core.gui.components.tree.MenuTree;
+import org.olat.core.gui.components.tree.TreeEvent;
+import org.olat.core.gui.components.tree.TreeModel;
+import org.olat.core.gui.components.tree.TreeNode;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.course.nodes.ArchiveOptions;
+import org.olat.course.nodes.AssessmentToolOptions;
+import org.olat.course.nodes.AssessmentToolOptions.AlternativeToIdentities;
+import org.olat.ims.qti21.model.QTI21StatisticSearchParams;
+import org.olat.ims.qti21.ui.statistics.QTI21StatisticResourceResult;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 05.08.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class QTI21RuntimeStatisticsController extends BasicController implements Activateable2 {
+
+	private MenuTree courseTree;
+	private Controller currentCtrl;
+	private LayoutMain3ColsController layoutCtr;
+
+	private final ArchiveOptions options;
+	private final QTI21StatisticSearchParams searchParams;
+	private final QTI21StatisticResourceResult resourceResult;
+	
+	public QTI21RuntimeStatisticsController(UserRequest ureq, WindowControl wControl, 
+			RepositoryEntry testEntry, AssessmentToolOptions asOptions) {
+		super(ureq, wControl);
+		this.options = new ArchiveOptions();
+		this.options.setGroup(asOptions.getGroup());
+		this.options.setIdentities(asOptions.getIdentities());
+		
+		searchParams = new QTI21StatisticSearchParams(testEntry, null, null);
+		if(asOptions.getGroup() != null) {
+			List<Group> bGroups = Collections.singletonList(asOptions.getGroup().getBaseGroup());
+			searchParams.setLimitToGroups(bGroups);
+		} else if(asOptions.getAlternativeToIdentities() != null) {
+			AlternativeToIdentities alt = asOptions.getAlternativeToIdentities();
+			searchParams.setMayViewAllUsersAssessments(alt.isMayViewAllUsersAssessments());
+			searchParams.setLimitToGroups(alt.getGroups());
+		}
+		
+		resourceResult = new QTI21StatisticResourceResult(testEntry, searchParams);
+		
+		TreeModel treeModel = resourceResult.getTreeModel();
+
+		courseTree = new MenuTree("qti21StatisticsTree");
+		courseTree.setTreeModel(treeModel);
+		courseTree.addListener(this);
+		
+		layoutCtr = new LayoutMain3ColsController(ureq, wControl, courseTree, new Panel("empty"), null);
+		putInitialPanel(layoutCtr.getInitialComponent());
+		
+		TreeNode rootNode = courseTree.getTreeModel().getRootNode();
+		doSelectNode(ureq, rootNode);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(entries == null || entries.isEmpty()) return;
+		
+		ContextEntry entry = entries.get(0);
+		if(entry.getOLATResourceable() != null && entry.getOLATResourceable().getResourceableTypeName() != null) {
+			String nodeId = entry.getOLATResourceable().getResourceableTypeName();
+			TreeNode nclr = courseTree.getTreeModel().getNodeById(nodeId);
+			if(nclr != null) {
+				String selNodeId = nclr.getIdent();
+				courseTree.setSelectedNodeId(selNodeId);
+				doSelectNode(ureq, nclr);
+			}
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(courseTree == source) {
+			if(event instanceof TreeEvent) {
+				TreeEvent te = (TreeEvent)event;
+				if(MenuTree.COMMAND_TREENODE_CLICKED.equals(te.getCommand())) {
+					String ident = te.getNodeId();
+					TreeNode selectedNode = courseTree.getTreeModel().getNodeById(ident);
+					doSelectNode(ureq, selectedNode);
+				}
+			}
+		}
+	}
+	
+	private void doSelectNode(UserRequest ureq, TreeNode selectedNode) {
+		removeAsListenerAndDispose(currentCtrl);
+		WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableInstance(selectedNode.getIdent(), 0l), null);
+		currentCtrl = resourceResult.getController(ureq, swControl, selectedNode, false);
+		if(currentCtrl != null) {
+			listenTo(currentCtrl);
+			layoutCtr.setCol3(currentCtrl.getInitialComponent());
+		} else {
+			layoutCtr.setCol3(new Panel("empty"));
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties
index 4e88d9d4073d93dc8fc15df97852c99d69cd91a8..d28e5f6308c53c7fc2ade2dd71967717059760fe 100644
--- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties
@@ -47,6 +47,8 @@ debug.outcomes=Output Daten
 debug.responses=Antworten Daten
 exploded.msg=Explodiert
 form.metadata.title=Title
+reset.test.data.title=Daten von Test zurücksetzen
+reset.test.data.text=Wollen Sie wirklich alle Daten von dem Test zurücksetzen? Die Resultate werden definitiv gelöscht.
 head.assessment.details=$org.olat.ims.qti\:head.ass.details
 head.assessment.overview=$org.olat.ims.qti\:head.ass.details
 interaction.order.drag.msg=Ziehen Sie die nicht verwendete Elemente von hier...
@@ -89,7 +91,7 @@ suspend.test=$org.olat.modules.iq\:suspendAssess
 tab.options=Optionen
 table.header.lastModified=$org.olat.course.nodes.iq\:table.header.lastModified
 table.header.results=$org.olat.course.nodes.iq\:table.header.results
-
+tab.reset.data=Daten zurücksetzen
 terminated.msg=Der Test ist beendet.
 test.complete=Test abgeschlossen
 test.entry.page.text=Der Test hat bis {0} Teile.
diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties
index 782bc1ccdc9b7fce20949b326e9336acddddef5d..38e302abef3aa642a1fa6254d6fdd58cb3680106 100644
--- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties
@@ -28,9 +28,9 @@ assessment.test.enter.test=Enter Test
 assessment.test.modal.feedback=Feedback
 assessment.test.multiPartTestMenu=Test part question menu
 assessment.test.nav.title.multiPartTestMenu=Test part question menu
-assessment.test.nav.title.questionMenu=Test Question Menu
-assessment.test.nextQuestion=Next Question
-assessment.test.questionMenu=Test Question Menu
+assessment.test.nav.title.questionMenu=Test question menu
+assessment.test.nextQuestion=Next question
+assessment.test.questionMenu=Test question menu
 assessment.test.suspended=The test has been suspended.
 assessment.testpart.config=Test part
 attemptsleft=$org.olat.modules.iq\:attemptsleft
@@ -50,6 +50,7 @@ error.input.invalid=Your input must be a valid {0}
 error.input.invalid.record=number
 error.input.invalid.string=text
 exploded.msg=Exploded
+menu.reset.title=Reset data of test
 form.metadata.title=Title
 head.assessment.details=$org.olat.ims.qti\:head.ass.details
 head.assessment.overview=$org.olat.ims.qti\:head.ass.details
@@ -96,6 +97,7 @@ serialize.error=An unexpected happens while saving the file.
 submit=Submit response
 suspend.test=$org.olat.modules.iq\:suspendAssess
 tab.options=Options
+tab.reset.data=Reset data
 table.header.lastModified=$org.olat.course.nodes.iq\:table.header.lastModified
 table.header.results=$org.olat.course.nodes.iq\:table.header.results
 terminated.msg=The test is finished.
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
index 61b2579d13c4c1953aea56d584bf61984dcceeb3..e46c64074d165474af1f2c3ae578777cc81f1bac 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
@@ -814,7 +814,13 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 		if(StringHelper.containsNonWhitespace(checkJavascript)) {
 			sb.append(" onchange=\"").append(checkJavascript).append("\">");
 		}
-		if(StringHelper.containsNonWhitespace(responseInputString)) {
+		
+		if(renderer.isSolutionMode()) {
+			String placeholder = interaction.getPlaceholderText();
+			if(StringHelper.containsNonWhitespace(placeholder)) {
+				sb.append(placeholder);
+			}
+		} else if( StringHelper.containsNonWhitespace(responseInputString)) {
 			sb.append(responseInputString);
 		}
 		sb.append("</textarea>");
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
index 4dc2bbfc3b1c28fbe2a66f9a0066ceea703803f8..a877f65b318ba8d7c872e1c0439a2201e72ee99a 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
@@ -229,7 +229,9 @@ public class AssessmentRenderFunctions {
 	}
 	
 	public static ResponseData getResponseInput(ItemSessionState itemSessionState, Identifier identifier) {
-		return itemSessionState.getRawResponseDataMap().get(identifier);
+		ResponseData responseInput =  itemSessionState.getRawResponseDataMap().get(identifier);
+		
+		return responseInput;
 	}
 	
 	public static String extractSingleCardinalityResponseInput(ResponseData data) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
index 28d4bdee476a04e59e463f8d5850ec52aa034144..231f01864a6dbbb76ff7335e0b6bf3e422d5f101 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
@@ -551,16 +551,16 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 			  .append(itemNode.getSectionPartTitle()).append("</span>");
 
 			if(!reviewable) {
-				sb.append("<span class='itemStatus reviewNotAllowed'>").append(translator.translate("assessment.item.status.reviewNot")).append("</span>");
+				sb.append("<span class='o_assessmentitem_status reviewNotAllowed'>").append(translator.translate("assessment.item.status.reviewNot")).append("</span>");
 			} else if(itemSessionState.getUnboundResponseIdentifiers().size() > 0
 					|| itemSessionState.getInvalidResponseIdentifiers().size() > 0) {
-				sb.append("<span class='itemStatus reviewInvalid'>").append(translator.translate("assessment.item.status.reviewInvalidAnswer")).append("</span>");
+				sb.append("<span class='o_assessmentitem_status reviewInvalid'>").append(translator.translate("assessment.item.status.reviewInvalidAnswer")).append("</span>");
 			} else if(itemSessionState.isResponded()) {
-				sb.append("<span class='itemStatus review'>").append(translator.translate("assessment.item.status.review")).append("</span>");
+				sb.append("<span class='o_assessmentitem_status review'>").append(translator.translate("assessment.item.status.review")).append("</span>");
 			} else if(itemSessionState.getEntryTime() != null) {
-				sb.append("<span class='itemStatus reviewNotAnswered'>").append(translator.translate("assessment.item.status.reviewNotAnswered")).append("</span>");
+				sb.append("<span class='o_assessmentitem_status reviewNotAnswered'>").append(translator.translate("assessment.item.status.reviewNotAnswered")).append("</span>");
 			} else {
-				sb.append("<span class='itemStatus reviewNotSeen'>").append(translator.translate("assessment.item.status.reviewNotSeen")).append("</span>");
+				sb.append("<span class='o_assessmentitem_status reviewNotSeen'>").append(translator.translate("assessment.item.status.reviewNotSeen")).append("</span>");
 			}
 			
 			sb.append("</button></li>");
@@ -606,7 +606,7 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 			boolean multiPartTest = component.hasMultipleTestParts();
 			String title = multiPartTest ?
 					translator.translate("assessment.test.nav.title.multiPartTestMenu") : translator.translate("assessment.test.nav.title.questionMenu");
-			sb.append("<h1>").append(title).append(" Question Menu</h1>");
+			sb.append("<h3>").append(title).append("</h3>");
 			
 			//part, sections and item refs
 			sb.append("<ul class='o_testpartnavigation list-unstyled'>");
@@ -651,7 +651,7 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 	private void renderNavigationAssessmentSection(AssessmentRenderer renderer, StringOutput sb, AssessmentTestComponent component, TestPlanNode sectionNode,
 			URLBuilder ubu, Translator translator) {
 		sb.append("<li class='o_assessmentsection o_qti_menu_item'>")
-		  .append("<header><h2>").append(sectionNode.getSectionPartTitle()).append("</h2>");
+		  .append("<header><h4>").append(sectionNode.getSectionPartTitle()).append("</h4>");
 		renderAssessmentSectionRubrickBlock(renderer, sb, component, sectionNode, ubu, translator);
 
 		sb.append("</header><ul class='o_testpartnavigation_inner list-unstyled'>");
@@ -686,16 +686,16 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 		
 		ItemSessionState itemSessionState = component.getItemSessionState(itemNode.getKey());
 		if(itemSessionState.getEndTime() != null) {
-			sb.append("<span class='itemStatus ended'>Finished</span>");
+			sb.append("<span class='o_assessmentitem_status ended'>Finished</span>");
 		} else if(itemSessionState.getUnboundResponseIdentifiers().size() > 0
 				|| itemSessionState.getInvalidResponseIdentifiers().size() > 0) {
-			sb.append("<span class='itemStatus invalid'>Needs Attention</span>");
+			sb.append("<span class='o_assessmentitem_status invalid'>Needs Attention</span>");
 		} else if(itemSessionState.isResponded() || itemSessionState.hasUncommittedResponseValues()) {
-			sb.append("<span class='itemStatus answered'>Answered</span>");
+			sb.append("<span class='o_assessmentitem_status answered'>Answered</span>");
 		} else if(itemSessionState.getEntryTime() != null) {
-			sb.append("<span class='itemStatus notAnswered'>Not Answered</span>");
+			sb.append("<span class='o_assessmentitem_status notAnswered'>Not Answered</span>");
 		} else {
-			sb.append("<span class='itemStatus notPresented'>").append(translator.translate("assessment.item.status.notSeen")).append("</span>");
+			sb.append("<span class='o_assessmentitem_status notPresented'>").append(translator.translate("assessment.item.status.notSeen")).append("</span>");
 		}
 		
 		sb.append("</button>");
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/InteractionResultComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/InteractionResultComponentRenderer.java
index 8ffa2952364157e1ce132f4dbcbf461b1e8f394b..61782b5f8e622779ccf04f3ffab53a86b3627a9c 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/InteractionResultComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/InteractionResultComponentRenderer.java
@@ -27,6 +27,7 @@ import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
 
 import uk.ac.ed.ph.jqtiplus.node.content.basic.Block;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.Flow;
 import uk.ac.ed.ph.jqtiplus.node.content.variable.PrintedVariable;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
@@ -60,6 +61,8 @@ public class InteractionResultComponentRenderer extends AssessmentObjectComponen
 		
 		if(interaction instanceof Block) {
 			renderBlock(assessmentRenderer, sb, cmp, resolvedAssessmentItem, itemSessionState, (Block)interaction, ubu, translator);
+		} else if(interaction instanceof Flow) {
+			renderFlow(assessmentRenderer, sb, cmp, resolvedAssessmentItem, itemSessionState, (Flow)interaction, ubu, translator);
 		}
 	}
 
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/extendedTextInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/extendedTextInteraction.html
index 681e1ea2fd70134b795a4506de61478673371fac..68b6e4bb5b34796734ebae3d99a829641cabcc8e 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/_content/extendedTextInteraction.html
+++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/extendedTextInteraction.html
@@ -14,7 +14,6 @@
 		$r.translate("error.input.invalid", $r.translate("error.input.invalid.${responseDeclaration.cardinality.toQtiString()}"))
 	</div>
 	#end
-      
 	#if($r.isInvalidResponse($interaction.responseIdentifier))
 		<div class="o_error badResponse">
 		## This will happen if either a pattern is wrong or the wrong number of choices were made
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/textEntryInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/textEntryInteraction.html
index d98deb143c39b0fc10a9aca7d216f975784504a1..4039f65d9eba10feae0f587b99d45c9cae70b882 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/_content/textEntryInteraction.html
+++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/textEntryInteraction.html
@@ -2,12 +2,13 @@
 #set($isBadResponse = $r.isBadResponse($interaction.responseIdentifier))
 #set($isInvalidResponse = $r.isInvalidResponse($interaction.responseIdentifier))
 #set($responseDeclaration = $r.getResponseDeclaration($interaction.responseIdentifier))
-#set($responseInput = $r.getResponseInput($interaction.responseIdentifier))
-#set($responseInputString = $r.extractSingleCardinalityResponseInput($responseInput))    
+#set($responseInput = $r.getResponseValue($interaction.responseIdentifier))
+#set($responseInputString = $r.toString($responseInput))
+
 #set($checkJavaScript = $r.checkJavaScript($responseDeclaration,$interaction.patternmask))
 <input name="qtiworks_presented_${responseIdentifier}" type="hidden" value="1"/>
 <span class="$localName">
-	<input id="od_${responseIdentifier}" type="text" name="qtiworks_response_${responseIdentifier}" #if($responseInputString && !$responseInputString.isEmpty()) value="$responseInputString" #else value="" #end $r.placeholder($interaction) #if($r.isItemSessionEnded()) disabled #end #if($isBadResponse) class='badResponse' #end #if($interaction.expectedLength) size='$interaction.expectedLength' #end #if($checks && $checks.size() > 0) onchange='$checkJavaScript' #end autocomplete="off"/>
+	<input id="od_${responseIdentifier}" type="text" name="qtiworks_response_${responseIdentifier}" #if($responseInputString && !$responseInputString.isEmpty()) value="$responseInputString" #else value="" #end #if(!$r.isItemSessionEnded()) $r.placeholder($interaction) #end #if($r.isItemSessionEnded()) disabled #end #if($isBadResponse) class='badResponse' #end #if($interaction.expectedLength) size='$interaction.expectedLength' #end #if($checks && $checks.size() > 0) onchange='$checkJavaScript' #end autocomplete="off"/>
 	#if($isBadResponse)
         <span class="badResponse">
         	You must enter a valid
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
index 39c7f4db3870983d5f35907b9015b98b43c30385..2d8daa1eb4d12bd0ba6b4d9d9696e48381a96582 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
@@ -37,6 +37,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.ims.qti.statistics.QTIType;
 import org.olat.ims.qti.statistics.model.StatisticsItem;
 import org.olat.ims.qti21.QTI21StatisticsManager;
+import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.QTI21StatisticSearchParams;
 import org.olat.ims.qti21.ui.statistics.interactions.ChoiceInteractionStatisticsController;
 import org.olat.ims.qti21.ui.statistics.interactions.HotspotInteractionStatisticsController;
@@ -89,9 +90,16 @@ public class QTI21AssessmentItemStatisticsController extends BasicController {
 		if(StringHelper.containsNonWhitespace(sectionTitle)) {
 			mainVC.contextPut("sectionTitle", sectionTitle);
 		}
-		mainVC.contextPut("numOfParticipants", resourceResult.getQTIStatisticAssessment().getNumOfParticipants());
+		mainVC.contextPut("numOfParticipants", numOfParticipants);
 		mainVC.contextPut("printMode", new Boolean(printMode));
 		
+		QTI21QuestionType type = QTI21QuestionType.getType(item);
+		if(type != null) {
+			mainVC.contextPut("itemCss", type.getCssClass());
+		} else {
+			mainVC.contextPut("itemCss", "o_mi_qtiunkown");
+		}
+		
 		StatisticsItem itemStats = initItemStatistics();
 		List<String> interactionIds = initInteractionControllers(ureq, itemStats);
 		mainVC.contextPut("interactionIds", interactionIds);
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
index 3615ce18ecc2bfc7056be80ab098c92e335941d6..65823f067631d52ce39c8312239ed687e0ae01ee 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
@@ -43,6 +43,7 @@ import org.olat.ims.qti.statistics.QTIType;
 import org.olat.ims.qti.statistics.model.StatisticAssessment;
 import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.QTI21StatisticsManager;
+import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.QTI21StatisticSearchParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -76,6 +77,10 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 	private final QTI21Service qtiService;
 	private final QTI21StatisticsManager qtiStatisticsManager;
 
+	public QTI21StatisticResourceResult(RepositoryEntry testEntry, QTI21StatisticSearchParams searchParams) {
+		this(testEntry, null, null, searchParams);
+	}
+	
 	public QTI21StatisticResourceResult(RepositoryEntry testEntry, RepositoryEntry courseEntry,
 			QTICourseNode courseNode, QTI21StatisticSearchParams searchParams) {
 		
@@ -119,7 +124,39 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 		URI itemUri = resolvedAssessmentTest.getSystemIdByItemRefMap().get(itemRef);
 		return new File(itemUri);
 	}
+	
+	/**
+	 * Return the tree model for a test learn resource.
+	 * 
+	 * @return
+	 */
+	public TreeModel getTreeModel() {
+		GenericTreeModel treeModel = new GenericTreeModel();
+		GenericTreeNode rootTreeNode = new GenericTreeNode();
+		treeModel.setRootNode(rootTreeNode);
+		
+		FileResourceManager frm = FileResourceManager.getInstance();
+		File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
+		resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false);
+		AssessmentTest test = resolvedAssessmentTest.getTestLookup().getRootNodeHolder().getRootNode();
+		
+		rootTreeNode.setTitle(test.getTitle());
+		rootTreeNode.setUserObject(test);
+		rootTreeNode.setIconCssClass("o_icon o_icon-lg o_qtiassessment_icon");
+		
+		//list all test parts
+		List<TestPart> parts = test.getChildAbstractParts();
+		int counter = 0;
+		for(TestPart part:parts) {
+			buildRecursively(part, ++counter, rootTreeNode);
+		}
+		return treeModel;
+	}
 
+	/**
+	 * Return the tree model for a course and a specific test.
+	 * 
+	 */
 	@Override
 	public TreeModel getSubTreeModel() {
 		GenericTreeModel subTreeModel = new GenericTreeModel();
@@ -191,7 +228,13 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 		if(ex == null) {
 			AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
 			itemNode.setTitle(assessmentItem.getTitle());
-			itemNode.setIconCssClass("o_icon o_mi_qtisc");
+			
+			QTI21QuestionType type = QTI21QuestionType.getType(assessmentItem);
+			if(type != null) {
+				itemNode.setIconCssClass("o_icon ".concat(type.getCssClass()));
+			} else {
+				itemNode.setIconCssClass("o_icon o_mi_qtiunkown");
+			}
 			itemNode.setUserObject(itemRef);
 			parentNode.addChild(itemNode);
 		}
@@ -201,40 +244,52 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 
 	@Override
 	public Controller getController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, TreeNode selectedNode) {
-		return getController(ureq, wControl, stackPanel, selectedNode, false);
+		return getController(ureq, wControl, selectedNode, false);
 	}
 	
-	public Controller getController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
+	public Controller getController(UserRequest ureq, WindowControl wControl,
 			TreeNode selectedNode, boolean printMode) {	
 		if(selectedNode instanceof StatisticResourceNode) {
-			return createAssessmentController(ureq, wControl, stackPanel, printMode);
+			return createAssessmentController(ureq, wControl, printMode);
 		} else {
 			Object uobject = selectedNode.getUserObject();
+			
 			if(uobject instanceof AssessmentItemRef) {
 				TreeNode parentNode = (TreeNode)selectedNode.getParent();
 				String sectionTitle = parentNode.getTitle();
-				return createAssessmentItemController(ureq, wControl, stackPanel,
+				return createAssessmentItemController(ureq, wControl,
 						(AssessmentItemRef)uobject, sectionTitle, printMode);
+			} else if(uobject instanceof AssessmentTest) {
+				return createAssessmentController(ureq, wControl, printMode);
 			}
 		}
 		return null;
 	}
 	
-	private Controller createAssessmentController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
+	private Controller createAssessmentController(UserRequest ureq, WindowControl wControl,
 			boolean printMode) {
-		Controller ctrl = new QTI21AssessmentTestStatisticsController(ureq, wControl, this, printMode);
-		CourseNodeConfiguration cnConfig = CourseNodeFactory.getInstance()
-				.getCourseNodeConfigurationEvenForDisabledBB(courseNode.getType());
-		String iconCssClass = cnConfig.getIconCSSClass();
-		return TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass);
+		Controller ctrl;
+		if(courseNode == null) {
+			ctrl = new QTI21AssessmentTestStatisticsController(ureq, wControl, testEntry, printMode);
+		} else {
+			ctrl = new QTI21AssessmentTestStatisticsController(ureq, wControl, this, printMode);
+			CourseNodeConfiguration cnConfig = CourseNodeFactory.getInstance()
+					.getCourseNodeConfigurationEvenForDisabledBB(courseNode.getType());
+			String iconCssClass = cnConfig.getIconCSSClass();
+			ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass);
+		}
+		return ctrl;
 	}
 	
-	private Controller createAssessmentItemController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
+	private Controller createAssessmentItemController(UserRequest ureq, WindowControl wControl,
 			AssessmentItemRef assessmentItemRef, String sectionTitle, boolean printMode) {
 		ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(assessmentItemRef);
 		AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
 		Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, assessmentItem, sectionTitle, this, printMode);
 		String iconCssClass = "o_mi_qtisc";
-		return TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass);
+		if(courseNode != null) {
+			ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass);
+		}
+		return ctrl;
 	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
index 1494ef953a6875e2b3ac48dab4238726e545329d..6f21adb2cb3fbdf0eb8ed4308a060092113025fe 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
@@ -2,7 +2,7 @@
 	#if($sectionTitle)
 	<h5>$r.translate("section"): $sectionTitle</h5>
 	#end
-	<h3><i class="o_icon $series.itemCss""> </i> $title</h3>
+	<h3><i class="o_icon $itemCss""> </i> $title</h3>
 	#if ($question && $question != "")
 		<h4>$r.translate("chart.item")</h4>
 		<div class="o_qti_statistics_question clearfix">$question</div>
diff --git a/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java
index 3e80f5039a842f6e24d446e80b14622c5a56c829..37bda08e0f92080a1ee47ed3686dd6c76d63dc3e 100644
--- a/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java
+++ b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java
@@ -31,6 +31,7 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.model.AssessmentEntryImpl;
+import org.olat.modules.assessment.model.AssessmentEntryStatus;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -176,6 +177,16 @@ public class AssessmentEntryDAO {
 		return entries.isEmpty() ? null : entries.get(0);
 	}
 	
+	public AssessmentEntry resetAssessmentEntry(AssessmentEntry nodeAssessment) {
+		nodeAssessment.setScore(null);
+		nodeAssessment.setPassed(null);
+		nodeAssessment.setAttempts(0);
+		nodeAssessment.setCompletion(null);
+		nodeAssessment.setAssessmentStatus(AssessmentEntryStatus.notStarted);
+		((AssessmentEntryImpl)nodeAssessment).setLastModified(new Date());
+		return dbInstance.getCurrentEntityManager().merge(nodeAssessment);
+	}
+	
 	public AssessmentEntry updateAssessmentEntry(AssessmentEntry nodeAssessment) {
 		((AssessmentEntryImpl)nodeAssessment).setLastModified(new Date());
 		return dbInstance.getCurrentEntityManager().merge(nodeAssessment);
diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
index 20f86dded2ea00771f8c5ba7068f92266f0ec6f1..3573c666794b1f91878445582ddc00c7abc7963f 100644
--- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
+++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
@@ -141,7 +141,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	private LockResult lockResult;
 	private boolean assessmentLock;// by Assessment mode
 	private AssessmentMode assessmentMode;
-	private final RepositoryHandler handler;
+	protected final RepositoryHandler handler;
 	private AtomicBoolean launchDateUpdated = new AtomicBoolean(false);
 	
 	private HistoryPoint launchedFromPoint;
@@ -155,7 +155,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	@Autowired
 	protected RepositoryModule repositoryModule;
 	@Autowired
-	private RepositoryService repositoryService;
+	protected RepositoryService repositoryService;
 	@Autowired
 	protected RepositoryManager repositoryManager;
 	@Autowired
@@ -299,6 +299,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		initRuntimeTools(toolsDropdown);
 		initSettingsTools(settingsDropdown);
 		initEditionTools(settingsDropdown);
+		initDeleteTools(settingsDropdown, true);
 
 		detailsLink = LinkFactory.createToolLink("details", translate("details.header"), this, "o_sel_repo_details");
 		detailsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_details");
@@ -385,34 +386,21 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 				settingsDropdown.addComponent(downloadLink);
 			}
 		}
-		
-		boolean canClose = OresHelper.isOfType(re.getOlatResource(), CourseModule.class);
-		boolean closeManged = RepositoryEntryManagedFlag.isManaged(re, RepositoryEntryManagedFlag.close);
-		
+	}
+	
+	protected void initDeleteTools(Dropdown settingsDropdown, boolean needSpacer) {
 		if(reSecurity.isEntryAdmin()) {
 			boolean deleteManaged = RepositoryEntryManagedFlag.isManaged(re, RepositoryEntryManagedFlag.delete);
-			if(settingsDropdown.size() > 0 && (canClose || !deleteManaged)) {
+			if(needSpacer && settingsDropdown.size() > 0 && !deleteManaged) {
 				settingsDropdown.addComponent(new Spacer("close-delete"));
 			}
-
-			if(canClose && (!closeManged || !deleteManaged)) {
-				// If a resource is closable (currently only course) and
-				// deletable (currently all resources) we offer those two
-				// actions in a separate page, unless both are managed
-				// operations. In that case we don't show anything at all.				
-				// If only one of the two actions are managed, we go to the
-				// separate page as well and show only the relevant action
-				// there.
-				lifeCycleChangeLink = LinkFactory.createToolLink("lifeCycleChange", translate("details.lifecycle.change"), this, "o_icon o_icon-fw o_icon_lifecycle");
-				settingsDropdown.addComponent(lifeCycleChangeLink);
-			} else {				
-				if(!deleteManaged) {
-					String type = translate(handler.getSupportedType());
-					String deleteTitle = translate("details.delete.alt", new String[]{ type });
-					deleteLink = LinkFactory.createToolLink("delete", deleteTitle, this, "o_icon o_icon-fw o_icon_delete_item");
-					deleteLink.setElementCssClass("o_sel_repo_close");
-					settingsDropdown.addComponent(deleteLink);
-				}
+	
+			if(!deleteManaged) {
+				String type = translate(handler.getSupportedType());
+				String deleteTitle = translate("details.delete.alt", new String[]{ type });
+				deleteLink = LinkFactory.createToolLink("delete", deleteTitle, this, "o_icon o_icon-fw o_icon_delete_item");
+				deleteLink.setElementCssClass("o_sel_repo_close");
+				settingsDropdown.addComponent(deleteLink);
 			}
 		}
 	}
@@ -904,7 +892,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	
 	protected void launchContent(UserRequest ureq, RepositoryEntrySecurity security) {
 		if(corrupted) {
-			runtimeController = new CorruptedCourseController(ureq, this.getWindowControl());
+			runtimeController = new CorruptedCourseController(ureq, getWindowControl());
 			listenTo(runtimeController);
 			toolbarPanel.rootController(re.getDisplayname(), runtimeController);
 		} else if(security.canLaunch()) {