From 190df7ac8cd71aac6f10e88ac74089c85cfeaa57 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Thu, 28 Apr 2016 11:32:39 +0200
Subject: [PATCH] OO-1593: implementation for most of the interactions

---
 .../nodes/iq/IQConfigurationController.java   |  18 +-
 .../qti/export/Archive_1_SelectNodeStep.java  |   8 +-
 .../org/olat/ims/qti/export/QTIArchiver.java  |  24 +++
 .../qti21/manager/CorrectResponsesUtil.java   | 187 ++++++++++++++++--
 .../manager/archive/QTI21ArchiveFormat.java   | 113 +++++------
 .../archive/SimpleContentRenderer.java        |  51 +++++
 .../AbstractAssociateInteractionArchive.java  | 108 ++++++++++
 .../AbstractChoiceInteractionArchive.java     |   2 +-
 .../AssociateInteractionArchive.java          |  15 +-
 .../DefaultInteractionArchive.java            |   4 +-
 .../GapMatchInteractionArchive.java           | 105 +++++++++-
 .../GraphicAssociateInteractionArchive.java   |  21 +-
 .../GraphicGapMatchInteractionArchive.java    |  77 +++++++-
 .../GraphicOrderInteractionArchive.java       |  70 ++++++-
 .../HottextInteractionArchive.java            |  96 ++++++++-
 .../InlineChoiceInteractionArchive.java       |  75 ++++++-
 .../interactions/InteractionArchive.java      |   2 +-
 .../interactions/MatchInteractionArchive.java | 112 ++++++++---
 .../NoOutputInteractionArchive.java           |  53 +++++
 .../interactions/OrderInteractionArchive.java |  89 +++++++++
 .../PositionObjectInteractionArchive.java     |   2 +
 .../SelectPointInteractionArchive.java        |  92 ++++++++-
 .../SliderInteractionArchive.java             |  54 +++++
 .../TextEntryInteractionArchive.java          |   2 +-
 .../manager/CorrectResponsesUtilTest.java     |  47 +++++
 .../java/org/olat/test/AllTestsJunit4.java    |   1 +
 26 files changed, 1271 insertions(+), 157 deletions(-)
 create mode 100644 src/main/java/org/olat/ims/qti21/manager/archive/SimpleContentRenderer.java
 create mode 100644 src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractAssociateInteractionArchive.java
 create mode 100644 src/main/java/org/olat/ims/qti21/manager/archive/interactions/NoOutputInteractionArchive.java
 create mode 100644 src/test/java/org/olat/ims/qti21/manager/CorrectResponsesUtilTest.java

diff --git a/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java b/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java
index 24098bb12b1..3f9ad986b87 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java
@@ -571,13 +571,17 @@ public class IQConfigurationController extends BasicController {
 
 	private boolean needManualCorrectionQTI21(AssessmentItemRef itemRef, ResolvedAssessmentTest resolvedAssessmentTest) {
 		ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef);
-		AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
-		List<Interaction> interactions = assessmentItem.getItemBody().findInteractions();
-		for(Interaction interaction:interactions) {
-			if(interaction instanceof UploadInteraction
-					|| interaction instanceof DrawingInteraction
-					|| interaction instanceof ExtendedTextInteraction) {
-				return true;
+		if(resolvedAssessmentItem != null
+				&& resolvedAssessmentItem.getItemLookup() != null
+				&& resolvedAssessmentItem.getItemLookup().getRootNodeHolder() != null) {
+			AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
+			List<Interaction> interactions = assessmentItem.getItemBody().findInteractions();
+			for(Interaction interaction:interactions) {
+				if(interaction instanceof UploadInteraction
+						|| interaction instanceof DrawingInteraction
+						|| interaction instanceof ExtendedTextInteraction) {
+					return true;
+				}
 			}
 		}
 		return false;
diff --git a/src/main/java/org/olat/ims/qti/export/Archive_1_SelectNodeStep.java b/src/main/java/org/olat/ims/qti/export/Archive_1_SelectNodeStep.java
index 322f5b1bbca..c0ec7405569 100644
--- a/src/main/java/org/olat/ims/qti/export/Archive_1_SelectNodeStep.java
+++ b/src/main/java/org/olat/ims/qti/export/Archive_1_SelectNodeStep.java
@@ -36,6 +36,7 @@ import org.olat.core.gui.control.generic.wizard.StepsEvent;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.id.OLATResourceable;
 import org.olat.course.assessment.model.AssessmentNodeData;
+import org.olat.ims.qti.export.QTIArchiver.Type;
 
 /**
  * 
@@ -110,7 +111,12 @@ public class Archive_1_SelectNodeStep extends BasicStep {
 		protected void event(UserRequest ureq, Controller source, Event event) {
 			if(source == selectCtrl) {
 				if(event instanceof SelectTestOrSurveyEvent) {
-					fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
+					QTIArchiver archiver = ((QTIArchiver)getFromRunContext("archiver"));
+					if(archiver.getType() == Type.onyx || archiver.getType() == Type.qti21) {
+						fireEvent(ureq, StepsEvent.INFORM_FINISHED);
+					} else {
+						fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
+					}
 				}
 			}
 			super.event(ureq, source, event);
diff --git a/src/main/java/org/olat/ims/qti/export/QTIArchiver.java b/src/main/java/org/olat/ims/qti/export/QTIArchiver.java
index d6ac021b02a..e46ae896daa 100644
--- a/src/main/java/org/olat/ims/qti/export/QTIArchiver.java
+++ b/src/main/java/org/olat/ims/qti/export/QTIArchiver.java
@@ -126,10 +126,34 @@ public class QTIArchiver {
 	}
 
 	public void setData(AssessmentNodeData data) {
+		this.type = null;
+		this.results = null;
 		this.data = data;
 		ICourse course = CourseFactory.loadCourse(courseOres);
 		courseNode = course.getRunStructure().getNode(data.getIdent());
 		getQTIItemConfigs();
+		getType();
+	}
+	
+	public Type getType() {
+		if(type == null) {
+			if (courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_TYPE_QTI) != null) {
+				boolean isOnyx = courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_TYPE_QTI).equals(IQEditController.CONFIG_VALUE_QTI2);
+				if(isOnyx) {
+					type = Type.onyx;
+				}
+			}
+			
+			if(type != Type.onyx) {
+				RepositoryEntry testRe = courseNode.getReferencedRepositoryEntry();
+				if(ImsQTI21Resource.TYPE_NAME.equals(testRe.getOlatResource().getResourceableTypeName())) {
+			    	type = Type.qti21;
+			    } else {
+			    	type = Type.qti12;
+			    }
+			}
+		}
+		return type;
 	}
 	
 	public boolean hasResults() {
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 409285777f1..e1b690b6ebd 100644
--- a/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java
+++ b/src/main/java/org/olat/ims/qti21/manager/CorrectResponsesUtil.java
@@ -25,13 +25,14 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 
 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.interaction.MatchInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.MapEntry;
 import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.shared.FieldValue;
@@ -39,7 +40,11 @@ import uk.ac.ed.ph.jqtiplus.types.Identifier;
 import uk.ac.ed.ph.jqtiplus.value.Cardinality;
 import uk.ac.ed.ph.jqtiplus.value.DirectedPairValue;
 import uk.ac.ed.ph.jqtiplus.value.IdentifierValue;
+import uk.ac.ed.ph.jqtiplus.value.IntegerValue;
 import uk.ac.ed.ph.jqtiplus.value.MultipleValue;
+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;
@@ -54,6 +59,8 @@ import uk.ac.ed.ph.jqtiplus.value.Value;
  */
 public class CorrectResponsesUtil {
 	
+	private static final OLog log = Tracing.createLoggerFor(CorrectResponsesUtil.class);
+	
 	/**
 	 * Remove the leading and trailing [ ] if exists.
 	 * @param stringuifiedResponses
@@ -71,6 +78,58 @@ public class CorrectResponsesUtil {
 		return stringuifiedResponses;
 	}
 	
+	/**
+	 * Parse response in the form [34 45][test] and return "23 45", test.
+	 * @return
+	 */
+	public static final List<String> parseResponses(String stringuifiedResponse) {
+		List<String> responses = new ArrayList<>();
+		if(StringHelper.containsNonWhitespace(stringuifiedResponse)) {
+			StringBuilder sb = new StringBuilder();
+			int numOfChars = stringuifiedResponse.length();
+			for(int i=0;i<numOfChars; i++) {
+				char ch = stringuifiedResponse.charAt(i);
+				if(ch == '[') {
+					sb = new StringBuilder();
+				} else if(ch == ']') {
+					responses.add(sb.toString());
+				} else {
+					sb.append(ch);
+				}
+			}
+		}
+		return responses;
+	}
+	
+	/**
+	 * The method ignore the wrong formatted coordinates
+	 * @param responses
+	 * @return
+	 */
+	public static final List<PointValue> parseResponses(List<String> responses) {
+		List<PointValue> points = new ArrayList<>();
+		for(String response:responses) {
+			if(StringHelper.containsNonWhitespace(response)) {
+				try {
+					PointValue pointValue = PointValue.parseString(response);
+					points.add(pointValue);
+				} catch (Exception e) {
+					log.error("", e);
+				}
+			}
+		}
+		return points;
+	}
+	
+	public static final int[] convertCoordinates(final List<Integer> coords) {
+        final int[] result = new int[coords.size()];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = coords.get(i).intValue();
+        }
+
+        return result;
+    }
+	
 	/**
 	 * Calculate the list of correct responses found in the response of the assessed user.
 	 * 
@@ -137,31 +196,129 @@ public class CorrectResponsesUtil {
 		return correctAnswers;
 	}
 	
+	public static final List<Integer> getCorrectIntegerResponses(AssessmentItem assessmentItem, Interaction interaction) {
+		List<Integer> correctAnswers = new ArrayList<>(5);
+		
+		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
+		if(responseDeclaration != null && responseDeclaration.getCorrectResponse() != null) {
+			CorrectResponse correctResponse = responseDeclaration.getCorrectResponse();
+			if(correctResponse.getCardinality().isOneOf(Cardinality.SINGLE)) {
+				List<FieldValue> values = correctResponse.getFieldValues();
+				Value value = FieldValue.computeValue(Cardinality.SINGLE, values);
+				if(value instanceof IntegerValue) {
+					IntegerValue identifierValue = (IntegerValue)value;
+					correctAnswers.add(identifierValue.intValue());
+				}
+				
+			} else if(correctResponse.getCardinality().isOneOf(Cardinality.MULTIPLE)) {
+				Value value = FieldValue.computeValue(Cardinality.MULTIPLE, correctResponse.getFieldValues());
+				if(value instanceof MultipleValue) {
+					MultipleValue multiValue = (MultipleValue)value;
+					for(SingleValue sValue:multiValue.getAll()) {
+						if(sValue instanceof IntegerValue) {
+							IntegerValue identifierValue = (IntegerValue)value;
+							correctAnswers.add(identifierValue.intValue());
+						}
+					}
+				}
+			}
+		}
+		
+		return correctAnswers;
+	}
+	
+	
+	public static final List<Identifier> getCorrectOrderedIdentifierResponses(AssessmentItem assessmentItem, Interaction interaction) {
+		List<Identifier> correctAnswers = new ArrayList<>(5);
+		
+		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
+		if(responseDeclaration != null && responseDeclaration.getCorrectResponse() != null) {
+			CorrectResponse correctResponse = responseDeclaration.getCorrectResponse();
+			if(correctResponse.getCardinality().isOneOf(Cardinality.ORDERED)) {
+				List<FieldValue> values = correctResponse.getFieldValues();
+				Value value = FieldValue.computeValue(Cardinality.ORDERED, values);
+				if(value instanceof OrderedValue) {
+					OrderedValue multiValue = (OrderedValue)value;
+					multiValue.forEach(oValue -> {
+						if(oValue instanceof IdentifierValue) {
+							IdentifierValue identifierValue = (IdentifierValue)oValue;
+							Identifier correctAnswer = identifierValue.identifierValue();
+							correctAnswers.add(correctAnswer);
+						}
+						
+					});
+				}
+			}
+		}
+
+		return correctAnswers;
+	}
+	
+	public static final List<String> getCorrectMultiplePairResponses(AssessmentItem assessmentItem, Interaction interaction, boolean withDelimiter) {
+		final List<String> correctAnswers = new ArrayList<>(5);
+		
+		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
+		if(responseDeclaration != null && responseDeclaration.getCorrectResponse() != null) {
+			CorrectResponse correctResponse = responseDeclaration.getCorrectResponse();
+			if(correctResponse.getCardinality().isOneOf(Cardinality.MULTIPLE)) {
+				List<FieldValue> values = correctResponse.getFieldValues();
+				Value value = FieldValue.computeValue(Cardinality.MULTIPLE, values);
+				if(value instanceof MultipleValue) {
+					MultipleValue multiValue = (MultipleValue)value;
+					multiValue.forEach(oValue -> {
+						if(oValue instanceof PairValue) {
+							PairValue pairValue = (PairValue)oValue;
+							String source = pairValue.sourceValue().toString();
+							String destination = pairValue.destValue().toString();
+							if(withDelimiter) {
+								correctAnswers.add("[" + source + " " + destination + "]");
+							} else {
+								correctAnswers.add(source + " " + destination);
+							}
+						}
+					});
+				}
+			}
+		}
+		return correctAnswers;
+	}
+	
 	/**
 	 * The list of correct associations
 	 * @param assessmentItem
 	 * @param interaction
 	 * @return A list of string with [ and ] before and after!
 	 */
-	public static final Set<String> getCorrectKPrimResponses(AssessmentItem assessmentItem, MatchInteraction interaction) {
+	public static final Set<String> getCorrectDirectPairResponses(AssessmentItem assessmentItem, Interaction interaction, boolean withDelimiter) {
 		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
-		
+
+		Set<String> correctAnswers = new HashSet<>();
 		//readable responses
-		Set<String> rightResponses = new HashSet<>();
-		List<MapEntry> mapEntries = responseDeclaration.getMapping().getMapEntries();
-		for(MapEntry mapEntry:mapEntries) {
-			SingleValue mapKey = mapEntry.getMapKey();
-			if(mapKey instanceof DirectedPairValue) {
-				DirectedPairValue pairValue = (DirectedPairValue)mapKey;
-				String source = pairValue.sourceValue().toString();
-				String destination = pairValue.destValue().toString();
-				rightResponses.add("[" + source + " " + destination + "]");
-			}
+		if(responseDeclaration != null && responseDeclaration.getCorrectResponse() != null) {
+			CorrectResponse correctResponse = responseDeclaration.getCorrectResponse();
+			if(correctResponse.getCardinality().isOneOf(Cardinality.MULTIPLE)) {
+				List<FieldValue> values = correctResponse.getFieldValues();
+				Value value = FieldValue.computeValue(Cardinality.MULTIPLE, values);
+				if(value instanceof MultipleValue) {
+					MultipleValue multiValue = (MultipleValue)value;
+					multiValue.forEach(oValue -> {
+						if(oValue instanceof DirectedPairValue) {
+							DirectedPairValue pairValue = (DirectedPairValue)oValue;
+							String source = pairValue.sourceValue().toString();
+							String destination = pairValue.destValue().toString();
+							if(withDelimiter) {
+								correctAnswers.add("[" + source + " " + destination + "]");
+							} else {
+								correctAnswers.add(source + " " + destination);
+							}
+						}
+					});
+				}
+			} 
 		}
 		
-		return rightResponses;
+		return correctAnswers;
 	}
-
 	
 	public static final TextEntry getCorrectTextResponses(AssessmentItem assessmentItem, Interaction interaction) {
 		ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(interaction.getResponseIdentifier());
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 4b0130978ec..467014b488f 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
@@ -59,6 +59,7 @@ 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;
@@ -122,7 +123,8 @@ public class QTI21ArchiveFormat {
 	
 	private ResolvedAssessmentTest resolvedAssessmentTest;
 	private List<UserPropertyHandler> userPropertyHandlers;
-	private final Map<String,ItemInfos> itemInfosMap = new HashMap<>();
+
+	private List<ItemInfos> itemInfos;
 	private final Map<String, InteractionArchive> interactionArchiveMap = new HashMap<>();
 	
 	private final QTI21Service qtiService;
@@ -143,29 +145,29 @@ public class QTI21ArchiveFormat {
 	}
 	
 	private void initInteractionWriters() {
-		interactionArchiveMap.put(AssociateInteraction.QTI_CLASS_NAME, new AssociateInteractionArchive());
-		interactionArchiveMap.put(ChoiceInteraction.QTI_CLASS_NAME, new ChoiceInteractionArchive());
-		interactionArchiveMap.put(DrawingInteraction.QTI_CLASS_NAME, new DefaultInteractionArchive());//like file
-		interactionArchiveMap.put(ExtendedTextInteraction.QTI_CLASS_NAME, new ExtendedTextInteractionArchive());
-		interactionArchiveMap.put(GapMatchInteraction.QTI_CLASS_NAME, new GapMatchInteractionArchive());
-		interactionArchiveMap.put(GraphicAssociateInteraction.QTI_CLASS_NAME, new GraphicAssociateInteractionArchive());
-		interactionArchiveMap.put(GraphicGapMatchInteraction.QTI_CLASS_NAME, new GraphicGapMatchInteractionArchive());
-		interactionArchiveMap.put(GraphicOrderInteraction.QTI_CLASS_NAME, new GraphicOrderInteractionArchive()); 
-		interactionArchiveMap.put(HotspotInteraction.QTI_CLASS_NAME, new HotspotInteractionArchive());
-		interactionArchiveMap.put(SelectPointInteraction.QTI_CLASS_NAME, new SelectPointInteractionArchive());
-		interactionArchiveMap.put(HottextInteraction.QTI_CLASS_NAME, new HottextInteractionArchive());
-		interactionArchiveMap.put(MatchInteraction.QTI_CLASS_NAME, new MatchInteractionArchive());//only kprim
+		interactionArchiveMap.put(AssociateInteraction.QTI_CLASS_NAME, new AssociateInteractionArchive());					//ok
+		interactionArchiveMap.put(ChoiceInteraction.QTI_CLASS_NAME, new ChoiceInteractionArchive());						//ok
+		interactionArchiveMap.put(DrawingInteraction.QTI_CLASS_NAME, new DefaultInteractionArchive());						//like file
+		interactionArchiveMap.put(ExtendedTextInteraction.QTI_CLASS_NAME, new ExtendedTextInteractionArchive());			//ok
+		interactionArchiveMap.put(GapMatchInteraction.QTI_CLASS_NAME, new GapMatchInteractionArchive());					//ok
+		interactionArchiveMap.put(GraphicAssociateInteraction.QTI_CLASS_NAME, new GraphicAssociateInteractionArchive());	//ok
+		interactionArchiveMap.put(GraphicGapMatchInteraction.QTI_CLASS_NAME, new GraphicGapMatchInteractionArchive());		//ok
+		interactionArchiveMap.put(GraphicOrderInteraction.QTI_CLASS_NAME, new GraphicOrderInteractionArchive()); 			//ok
+		interactionArchiveMap.put(HotspotInteraction.QTI_CLASS_NAME, new HotspotInteractionArchive());						//ok
+		interactionArchiveMap.put(SelectPointInteraction.QTI_CLASS_NAME, new SelectPointInteractionArchive());				//ok
+		interactionArchiveMap.put(HottextInteraction.QTI_CLASS_NAME, new HottextInteractionArchive());						//ok
+		interactionArchiveMap.put(MatchInteraction.QTI_CLASS_NAME, new MatchInteractionArchive());							//ok
 		interactionArchiveMap.put(MediaInteraction.QTI_CLASS_NAME, new MediaInteractionArchive());
-		interactionArchiveMap.put(OrderInteraction.QTI_CLASS_NAME, new OrderInteractionArchive());
+		interactionArchiveMap.put(OrderInteraction.QTI_CLASS_NAME, new OrderInteractionArchive());							//ok
 		interactionArchiveMap.put(PositionObjectInteraction.QTI_CLASS_NAME, new PositionObjectInteractionArchive());
-		interactionArchiveMap.put(SliderInteraction.QTI_CLASS_NAME, new SliderInteractionArchive());
+		interactionArchiveMap.put(SliderInteraction.QTI_CLASS_NAME, new SliderInteractionArchive());						//ok
 		interactionArchiveMap.put(UploadInteraction.QTI_CLASS_NAME, new DefaultInteractionArchive());
 	//custom
-		interactionArchiveMap.put(CustomInteraction.QTI_CLASS_NAME, new DefaultInteractionArchive());
+		interactionArchiveMap.put(CustomInteraction.QTI_CLASS_NAME, new NoOutputInteractionArchive());						//ok
 	//inline
-		interactionArchiveMap.put(EndAttemptInteraction.QTI_CLASS_NAME, new DefaultInteractionArchive());//not really usefull
-		interactionArchiveMap.put(InlineChoiceInteraction.QTI_CLASS_NAME, new InlineChoiceInteractionArchive());
-		interactionArchiveMap.put(TextEntryInteraction.QTI_CLASS_NAME, new TextEntryInteractionArchive());
+		interactionArchiveMap.put(EndAttemptInteraction.QTI_CLASS_NAME, new NoOutputInteractionArchive());					//ok
+		interactionArchiveMap.put(InlineChoiceInteraction.QTI_CLASS_NAME, new InlineChoiceInteractionArchive());			//ok
+		interactionArchiveMap.put(TextEntryInteraction.QTI_CLASS_NAME, new TextEntryInteractionArchive());					//ok
 	}
 	
 	public boolean hasResults(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) {
@@ -216,18 +218,14 @@ public class QTI21ArchiveFormat {
 		}
 		col += 5;// homepage -> test duration
 		
-		List<AssessmentItemRef> itemRefs = getAssessmentItemRefs();
-		for(int i=0; i<itemRefs.size(); i++) {
-			AssessmentItemRef itemRef = itemRefs.get(i);
-			ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef);
-			AssessmentItem item = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
-			
-			ItemInfos itemInfos = getItemInfos(itemRef);
-			List<Interaction> interactions = itemInfos.getInteractions();
+		List<ItemInfos> infos = getItemInfos();
+		for(int i=0; i<infos.size(); i++) {
+			ItemInfos item = infos.get(i);
+			List<Interaction> interactions = item.getInteractions();
 			for(int j=0; j<interactions.size(); j++) {
 				Interaction interaction = interactions.get(j);
 				col = interactionArchiveMap.get(interaction.getQtiClassName())
-						.writeHeader1(item, interaction, i, j, header1Row, col, workbook);
+						.writeHeader1(item.getAssessmentItem(), interaction, i, j, header1Row, col, workbook);
 			}
 			col += 3;//score, start, duration
 		}
@@ -256,16 +254,15 @@ public class QTI21ArchiveFormat {
 		//header2Row.addCell(col++, translator.translate("column.header.ipaddress"), headerStyle);
 		header2Row.addCell(col++, translator.translate("column.header.date"), headerStyle);
 		header2Row.addCell(col++, translator.translate("column.header.duration"), headerStyle);
-		
-		List<AssessmentItemRef> itemRefs = getAssessmentItemRefs();
-		for(int i=0; i<itemRefs.size(); i++) {
-			AssessmentItemRef itemRef = itemRefs.get(i);
-			ItemInfos itemInfos = getItemInfos(itemRef);
-			List<Interaction> interactions = itemInfos.getInteractions();
+
+		List<ItemInfos> infos = getItemInfos();
+		for(int i=0; i<infos.size(); i++) {
+			ItemInfos info = infos.get(i);
+			List<Interaction> interactions = info.getInteractions();
 			for(int j=0; j<interactions.size(); j++) {
 				Interaction interaction = interactions.get(j);
 				col = interactionArchiveMap.get(interaction.getQtiClassName())
-						.writeHeader2(interaction, i, j, header2Row, col, workbook);
+						.writeHeader2(info.getAssessmentItem(), interaction, i, j, header2Row, col, workbook);
 			}
 
 			header2Row.addCell(col++, translator.translate("item.score"), headerStyle);
@@ -329,22 +326,21 @@ public class QTI21ArchiveFormat {
 		//dataRow.addCell(col++, "0.0.0.1", null);
 		dataRow.addCell(col++, testSession.getCreationDate(), workbook.getStyles().getDateStyle());
 		dataRow.addCell(col++, toDurationInMilliseconds(testSession.getDuration()), null);
-		
-		List<AssessmentItemRef> itemRefs = getAssessmentItemRefs();
-		for(int i=0; i<itemRefs.size(); i++) {
-			AssessmentItemRef itemRef = itemRefs.get(i);
+
+		List<ItemInfos> infos = getItemInfos();
+		for(int i=0; i<infos.size(); i++) {
+			ItemInfos info = infos.get(i);
+			AssessmentItemRef itemRef = info.getAssessmentItemRef();
 			String itemRefIdentifier = itemRef.getIdentifier().toString();
 			AssessmentItemSession itemSession = responses.getItemSession(itemRefIdentifier);
-			ItemInfos itemInfos = getItemInfos(itemRef);
-			AssessmentItem item = itemInfos.getAssessmentItem();
-
-			List<Interaction> interactions = itemInfos.getInteractions();
+			
+			List<Interaction> interactions = info.getInteractions();
 			for(int j=0; j<interactions.size(); j++) {
 				Interaction interaction = interactions.get(j);
 				 AssessmentResponse response = responses
 						 .getResponse(itemRefIdentifier, interaction.getResponseIdentifier());
 				col = interactionArchiveMap.get(interaction.getQtiClassName())
-							.writeInteractionData(item, response, interaction, j, dataRow, col, workbook);
+							.writeInteractionData(info.getAssessmentItem(), response, interaction, j, dataRow, col, workbook);
 			}
 			
 			//score, start, duration
@@ -363,18 +359,17 @@ public class QTI21ArchiveFormat {
 		return value.longValue() / 1000l;
 	}
 	
-	private List<AssessmentItemRef> getAssessmentItemRefs() {
-		return resolvedAssessmentTest.getAssessmentItemRefs();
-	}
-	
-	private ItemInfos getItemInfos(AssessmentItemRef itemRef) {
-		String itemRefIdentifier = itemRef.getIdentifier().toString();
-		ItemInfos itemInfos = itemInfosMap.get(itemRefIdentifier);
+	private List<ItemInfos> getItemInfos() {
 		if(itemInfos == null) {
-			ResolvedAssessmentItem resolvedItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef);
-			AssessmentItem item = resolvedItem.getRootNodeLookup().extractIfSuccessful();
-			itemInfos = new ItemInfos(item, item.getItemBody().findInteractions());
-			itemInfosMap.put(itemRefIdentifier, itemInfos);
+			itemInfos = new ArrayList<>();
+			List<AssessmentItemRef> itemRefs = resolvedAssessmentTest.getAssessmentItemRefs();
+			for(AssessmentItemRef itemRef:itemRefs) {
+				ResolvedAssessmentItem resolvedItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef);
+				AssessmentItem item = resolvedItem.getRootNodeLookup().extractIfSuccessful();
+				if(item != null) {
+					itemInfos.add(new ItemInfos(itemRef, item, item.getItemBody().findInteractions()));
+				}
+			}
 		}
 		return itemInfos;
 	}
@@ -430,14 +425,20 @@ public class QTI21ArchiveFormat {
 	
 	private static class ItemInfos {
 		
+		private final AssessmentItemRef itemRef;
 		private final AssessmentItem assessmentItem;
 		private final List<Interaction> interactions;
 		
-		public ItemInfos(AssessmentItem assessmentItem, List<Interaction> interactions) {
+		public ItemInfos(AssessmentItemRef itemRef, AssessmentItem assessmentItem, List<Interaction> interactions) {
+			this.itemRef = itemRef;
 			this.interactions = interactions;
 			this.assessmentItem = assessmentItem;
 		}
 		
+		public AssessmentItemRef getAssessmentItemRef() {
+			return itemRef;
+		}
+		
 		public AssessmentItem getAssessmentItem() {
 			return assessmentItem;
 		}
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/SimpleContentRenderer.java b/src/main/java/org/olat/ims/qti21/manager/archive/SimpleContentRenderer.java
new file mode 100644
index 00000000000..cbae8569a51
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/SimpleContentRenderer.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.ims.qti21.manager.archive;
+
+import java.util.List;
+
+import uk.ac.ed.ph.jqtiplus.node.QtiNode;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun;
+
+/**
+ * 
+ * Initial date: 28.04.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SimpleContentRenderer {
+	
+	public static final String renderFlowStatics(List<FlowStatic> flowStatics) {
+		StringBuilder sb = new StringBuilder();
+		for(FlowStatic flowStatic:flowStatics) {
+			render(sb, flowStatic);
+		}
+		
+		return sb.toString();
+	}
+	
+	private static void render(StringBuilder sb, QtiNode node) {
+		if(node instanceof TextRun) {
+			sb.append(((TextRun)node).getTextContent());
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractAssociateInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractAssociateInteractionArchive.java
new file mode 100644
index 00000000000..d6be6c0aef1
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractAssociateInteractionArchive.java
@@ -0,0 +1,108 @@
+/**
+ * <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.manager.archive.interactions;
+
+import java.util.List;
+
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+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 uk.ac.ed.ph.jqtiplus.internal.util.Pair;
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.types.DataTypeBinder;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
+
+/**
+ * 
+ * Initial date: 28.04.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+abstract class AbstractAssociateInteractionArchive extends DefaultInteractionArchive {
+	
+	private static final OLog log = Tracing.createLoggerFor(AbstractAssociateInteractionArchive.class);
+
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		int maxAssociation = getMaxAssociations(interaction);
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
+		col += Math.max(1, maxAssociation);
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		int maxAssociation = getMaxAssociations(interaction);
+		if(maxAssociation > 0) {
+			for(int i=0; i<maxAssociation; i++) {
+				String header = (itemNumber + 1) + "_A" + i;
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
+			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		int maxAssociation = getMaxAssociations(interaction);
+		
+		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+		List<String> responsesAssociations = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+		List<String> correctAnswers = CorrectResponsesUtil.getCorrectMultiplePairResponses(item, interaction, false);
+		
+		for(int i=0; i<maxAssociation; i++) {
+			String association = null;
+			String reverseAssociation = null;
+			if(responsesAssociations.size() > i) {
+				association = responsesAssociations.get(i);
+				try {
+					Pair<Identifier, Identifier> pair = DataTypeBinder.parsePair(association);
+					reverseAssociation = pair.getSecond() + " " + pair.getFirst();
+				} catch (Exception e) {
+					log.error("", e);
+					association = null;
+				}
+			}
+			
+			if(association == null) {
+				col++;
+			} else if(correctAnswers.contains(association) || correctAnswers.contains(reverseAssociation)) {
+				dataRow.addCell(col++, association, workbook.getStyles().getCorrectStyle());
+			} else {
+				dataRow.addCell(col++, association, null);
+			}
+		}
+		return col;
+	}
+	
+	protected abstract int getMaxAssociations(Interaction associateInteraction);
+
+}
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractChoiceInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractChoiceInteractionArchive.java
index 516d9421726..625d5c5ef68 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractChoiceInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AbstractChoiceInteractionArchive.java
@@ -55,7 +55,7 @@ public abstract class AbstractChoiceInteractionArchive extends DefaultInteractio
 	}
 
 	@Override
-	public int writeHeader2(Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		List<? extends Choice> choices = getChoices(interaction);
 		for(int i=0; i<choices.size(); i++) {
 			String header = (itemNumber + 1) + "_C" + i;
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AssociateInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AssociateInteractionArchive.java
index 23fb16ae43f..18c463537bf 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AssociateInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/AssociateInteractionArchive.java
@@ -19,12 +19,25 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.AssociateInteraction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+
 /**
  * 
  * Initial date: 26.04.2016<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class AssociateInteractionArchive extends DefaultInteractionArchive {
+public class AssociateInteractionArchive extends AbstractAssociateInteractionArchive {
+
+	@Override
+	protected int getMaxAssociations(Interaction interaction) {
+		AssociateInteraction associateInteraction = (AssociateInteraction)interaction;
+		int max = associateInteraction.getMaxAssociations();
+		if(max == 0) {
+			max = associateInteraction.getSimpleAssociableChoices().size() * (associateInteraction.getSimpleAssociableChoices().size() - 1);
+		}
+		return max;
+	}
 
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/DefaultInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/DefaultInteractionArchive.java
index 9210931c339..c62b38af50b 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/DefaultInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/DefaultInteractionArchive.java
@@ -46,7 +46,7 @@ public class DefaultInteractionArchive implements InteractionArchive {
 	}
 
 	@Override
-	public int writeHeader2(Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		String header = (itemNumber + 1) + "_U" + (interactionNumber + 1);;
 		dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
 		return col;
@@ -54,7 +54,7 @@ public class DefaultInteractionArchive implements InteractionArchive {
 
 	@Override
 	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
-		String choosed = response.getStringuifiedResponse();
+		String choosed = response == null ? null : response.getStringuifiedResponse();
 		dataRow.addCell(col++, choosed, null);
 		return col;
 	}
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GapMatchInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GapMatchInteractionArchive.java
index 010d8f26539..6172d9bc1d7 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GapMatchInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GapMatchInteractionArchive.java
@@ -19,13 +19,24 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
+import java.util.Set;
+
 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 uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun;
+import uk.ac.ed.ph.jqtiplus.node.content.variable.TextOrVariable;
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.GapMatchInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.GapChoice;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.GapText;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.content.Gap;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
+import uk.ac.ed.ph.jqtiplus.utils.QueryUtils;
 
 /**
  * 
@@ -35,12 +46,98 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
  */
 public class GapMatchInteractionArchive extends DefaultInteractionArchive  {
 	
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
+		col += Math.max(1, getGaps(interaction).size());
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		List<Gap> gaps = getGaps(interaction);
+		if(gaps.size() > 0) {
+			for(int i=0; i<gaps.size(); i++) {
+				String header = (itemNumber + 1) + "_G" + (i + 1);
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+	
 	@Override
 	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
 			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
-		GapMatchInteraction gapMatchInteraction = (GapMatchInteraction)interaction;
-		// choices but really associable choices
-		return super.writeInteractionData(item, response, gapMatchInteraction, itemNumber, dataRow, col, workbook);
+		
+		List<Gap> gaps = getGaps(interaction);
+		if(gaps.size() > 0) {
+			GapMatchInteraction gapMatchInteraction = (GapMatchInteraction)interaction;
+			
+			Set<String> correctAnswers = CorrectResponsesUtil.getCorrectDirectPairResponses(item, interaction, false);
+			String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+			List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+			
+			for(Gap gap:gaps) {
+				String gapIdentifier = gap.getIdentifier().toString();
+				
+				String gapResponse = null;
+				for(String r:responses) {
+					if(r.endsWith(gapIdentifier)) {
+						gapResponse = r;
+					}
+				}
+				
+				if(gapResponse != null) {
+					String[] gapResponsePair = gapResponse.split(" ");
+					if(gapResponsePair.length > 1) {
+						String gapResponseAssociation = gapResponsePair[0];
+						Identifier gapResponseIdentifier = Identifier.assumedLegal(gapResponseAssociation);
+						GapChoice choice = gapMatchInteraction.getGapChoice(gapResponseIdentifier);
+						String value = null;
+						if(choice != null) {
+							value = getTextContent(choice);
+						}
+						
+						boolean correct = correctAnswers.contains(gapResponse);
+						if(correct) {
+							dataRow.addCell(col++, value, workbook.getStyles().getCorrectStyle());
+						} else {
+							dataRow.addCell(col++, value);
+						}
+					} else {
+						col++;
+					}
+				} else {
+					col++;
+				}
+			}
+			
+		} else {
+			col++;
+		}
+		
+		return col;
+	}
+	
+	private String getTextContent(GapChoice selectedChoice) {
+		if(selectedChoice instanceof GapText) {
+			List<TextOrVariable> values = ((GapText)selectedChoice).getTextOrVariables();
+			for(TextOrVariable value:values) {
+				if(value instanceof TextRun) {
+					return ((TextRun)value).getTextContent();
+				}
+			}
+		}
+		return selectedChoice.getIdentifier().toString();
+	}
+	
+	public List<Gap> getGaps(Interaction interaction) {
+		List<Gap> gaps = QueryUtils.search(Gap.class, interaction.getNodeGroups().getBlockStaticGroup().getBlockStatics());
+		return gaps;
 	}
-
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicAssociateInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicAssociateInteractionArchive.java
index f121fd11091..1a45b5bd0b5 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicAssociateInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicAssociateInteractionArchive.java
@@ -19,11 +19,6 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
-import org.olat.core.util.openxml.OpenXMLWorkbook;
-import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
-import org.olat.ims.qti21.AssessmentResponse;
-
-import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicAssociateInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
 
@@ -33,15 +28,15 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class GraphicAssociateInteractionArchive extends DefaultInteractionArchive {
+public class GraphicAssociateInteractionArchive extends AbstractAssociateInteractionArchive {
 	
 	@Override
-	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
-			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+	protected int getMaxAssociations(Interaction interaction) {
 		GraphicAssociateInteraction associateInteraction = (GraphicAssociateInteraction)interaction;
-		associateInteraction.getAssociableHotspots();
-		// choices but really associable choices (hotspot) GraphicGapMatchInteraction
-		return super.writeInteractionData(item, response, associateInteraction, itemNumber, dataRow, col, workbook);
+		int max = associateInteraction.getMaxAssociations();
+		if(max == 0) {
+			max = associateInteraction.getAssociableHotspots().size() * (associateInteraction.getAssociableHotspots().size() - 1);
+		}
+		return max;
 	}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicGapMatchInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicGapMatchInteractionArchive.java
index 59a4f4ebd6c..41582e0f59b 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicGapMatchInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicGapMatchInteractionArchive.java
@@ -19,13 +19,18 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
+import java.util.Set;
+
 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 uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicGapMatchInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.graphic.AssociableHotspot;
 
 /**
  * 
@@ -34,13 +39,77 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
  *
  */
 public class GraphicGapMatchInteractionArchive extends DefaultInteractionArchive {
-	
+
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		}
+
+		GraphicGapMatchInteraction gapMatchInteraction = (GraphicGapMatchInteraction)interaction;
+		List<AssociableHotspot> spots = gapMatchInteraction.getAssociableHotspots();
+		if(spots.size() > 0) {
+			col += (spots.size() - 1);
+		}
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber,
+			Row dataRow, int col, OpenXMLWorkbook workbook) {
+
+		GraphicGapMatchInteraction gapMatchInteraction = (GraphicGapMatchInteraction)interaction;
+		List<AssociableHotspot> spots = gapMatchInteraction.getAssociableHotspots();
+		if(spots.size() > 0) {
+			for(int i=0; i<spots.size(); i++) {
+				String header = (itemNumber + 1) + "_GG" + (i + 1);
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+
 	@Override
 	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
 			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		GraphicGapMatchInteraction gapMatchInteraction = (GraphicGapMatchInteraction)interaction;
-		// choices but really associable choices (hotspot) like GraphicAssociateInteraction
-		return super.writeInteractionData(item, response, gapMatchInteraction, itemNumber, dataRow, col, workbook);
-	}
+		
+		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+		List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+		
+		Set<String> rightAnswers = CorrectResponsesUtil.getCorrectDirectPairResponses(item, interaction, false);
+		List<AssociableHotspot> spots = gapMatchInteraction.getAssociableHotspots();
+		for(AssociableHotspot spot:spots) {
+			String spotIdentifier = spot.getIdentifier().toString();
+			
+			String spotResponse = null;
+			for(String r:responses) {
+				if(r.endsWith(spotIdentifier)) {
+					spotResponse = r;
+				}
+			}
+			
+			if(spotResponse != null) {
+				String[] spotResponsePair = spotResponse.split(" ");
+				if(spotResponsePair.length > 1) {
+					String stopResponseAssociation = spotResponsePair[0];
+					boolean correct = rightAnswers.contains(spotResponse);
+					if(correct) {
+						dataRow.addCell(col++, stopResponseAssociation, workbook.getStyles().getCorrectStyle());
+					} else {
+						dataRow.addCell(col++, stopResponseAssociation);
+					}
+				} else {
+					col++;
+				}
+			} else {
+				col++;
+			}
+		}
 
+		return col;
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicOrderInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicOrderInteractionArchive.java
index b1409fa78cc..00dcb842139 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicOrderInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/GraphicOrderInteractionArchive.java
@@ -21,9 +21,16 @@ package org.olat.ims.qti21.manager.archive.interactions;
 
 import java.util.List;
 
+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 uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicOrderInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
-import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.Choice;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.graphic.HotspotChoice;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
 
 /**
  * 
@@ -31,12 +38,67 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.Choice;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class GraphicOrderInteractionArchive extends AbstractChoiceInteractionArchive {
+public class GraphicOrderInteractionArchive extends DefaultInteractionArchive {
+
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		}
+		
+		GraphicOrderInteraction orderInteraction = (GraphicOrderInteraction)interaction;
+		List<HotspotChoice> choices = orderInteraction.getHotspotChoices();
+		if(choices.size() > 0) {
+			col += (choices.size() - 1);
+		}
+		return col;
+	}
 
 	@Override
-	public List<? extends Choice> getChoices(Interaction interaction) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		GraphicOrderInteraction orderInteraction = (GraphicOrderInteraction)interaction;
-		return orderInteraction.getHotspotChoices();
+		List<HotspotChoice> choices = orderInteraction.getHotspotChoices();
+		if(choices.size() > 0) {
+			for(int i=0; i<choices.size(); i++) {
+				String header = (itemNumber + 1) + "_GO" + i;
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
 	}
 
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		GraphicOrderInteraction orderInteraction = (GraphicOrderInteraction)interaction;
+
+		List<HotspotChoice> choices = orderInteraction.getHotspotChoices();
+		if(choices.size() > 0) {
+			String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+			List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+			List<Identifier> correctAnswers = CorrectResponsesUtil.getCorrectOrderedIdentifierResponses(item, interaction);
+			
+			for(int i=0; i<choices.size(); i++) {
+				String currentResponse = null;
+				if(responses.size() > i) {
+					currentResponse = responses.get(i);
+				}
+				String correctAnswer = null;
+				if(correctAnswers.size() > i) {
+					correctAnswer = correctAnswers.get(i).toString();
+				}
+				
+				if(correctAnswer != null && correctAnswer.equals(currentResponse)) {
+					dataRow.addCell(col++, currentResponse, workbook.getStyles().getCorrectStyle());
+				} else {
+					dataRow.addCell(col++, currentResponse, null);
+				}
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/HottextInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/HottextInteractionArchive.java
index 2e92364b6e2..0746009af64 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/HottextInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/HottextInteractionArchive.java
@@ -19,13 +19,21 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
+
 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 uk.ac.ed.ph.jqtiplus.node.QtiNode;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.InlineStatic;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun;
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
-import uk.ac.ed.ph.jqtiplus.node.item.interaction.HottextInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.content.Hottext;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
+import uk.ac.ed.ph.jqtiplus.utils.QueryUtils;
 
 /**
  * 
@@ -34,14 +42,88 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
  *
  */
 public class HottextInteractionArchive extends DefaultInteractionArchive {
-	
+
 	@Override
-	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
-			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
-		HottextInteraction hottextInteraction = (HottextInteraction)interaction;
-		//scan for Hottext which are choices
-		return super.writeInteractionData(item, response, hottextInteraction, itemNumber, dataRow, col, workbook);
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		int numOfChoices = getHottexts(interaction).size();
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
+		col += Math.max(1, numOfChoices);
+		return col;
 	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		List<Hottext> texts = getHottexts(interaction);
+		if(texts.size() > 0) {
+			for(int i=0; i<texts.size(); i++) {
+				String header = (itemNumber + 1) + "_HT" + (i + 1);
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
 	
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+		List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+		List<Identifier> correctAnswers = CorrectResponsesUtil.getCorrectIdentifierResponses(item, interaction);
+		
+		List<Hottext> texts =  getHottexts(interaction);
+		for(int i=0; i<texts.size(); i++) {
+			Hottext text = texts.get(i);
+			Identifier textIdentifier = text.getIdentifier();
 
+			//user select this hot text
+			if(responses.contains(text.getIdentifier().toString())) {
+				String content = getContent(text);
+				//correct -> must be clicked
+				boolean correct = correctAnswers.contains(textIdentifier);
+				if(correct) {
+					dataRow.addCell(col++, content, workbook.getStyles().getCorrectStyle());
+				} else {
+					dataRow.addCell(col++, content, null);
+				}
+			} else {
+				//correct -> must not be clicked
+				boolean correct = !correctAnswers.contains(textIdentifier);
+				if(correct) {
+					dataRow.addCell(col++, "", workbook.getStyles().getCorrectStyle());
+				} else {
+					col++;
+				}
+			}
+		}
+		return col;
+	}
+	
+	private List<Hottext> getHottexts(Interaction interaction) {
+		List<Hottext> texts = QueryUtils.search(Hottext.class, interaction);
+		return texts;
+	}
+	
+	private String getContent(Hottext association) {
+		StringBuilder sb = new StringBuilder();
+		List<InlineStatic> inlineStatics = association.getInlineStatics();
+		for(InlineStatic inlineStatic:inlineStatics) {
+			renderContent(sb, inlineStatic);
+		}
+		
+		if(sb.length() > 0) {
+			return sb.toString();
+		}
+		return association.getIdentifier().toString();
+	}
+	
+	private void renderContent(StringBuilder sb, QtiNode node) {
+		if(node instanceof TextRun) {
+			sb.append(((TextRun)node).getTextContent());
+		}
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InlineChoiceInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InlineChoiceInteractionArchive.java
index e3876e3e8a2..ade3b72fc70 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InlineChoiceInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InlineChoiceInteractionArchive.java
@@ -21,9 +21,19 @@ package org.olat.ims.qti21.manager.archive.interactions;
 
 import java.util.List;
 
+import org.olat.core.util.StringHelper;
+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 uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun;
+import uk.ac.ed.ph.jqtiplus.node.content.variable.TextOrVariable;
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.InlineChoiceInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
-import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.Choice;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.InlineChoice;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
 
 /**
  * 
@@ -31,12 +41,69 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.Choice;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class InlineChoiceInteractionArchive extends AbstractChoiceInteractionArchive {
+public class InlineChoiceInteractionArchive extends DefaultInteractionArchive {
+	
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
+
+		col += 1;
+		return col;
+	}
 
 	@Override
-	public List<? extends Choice> getChoices(Interaction interaction) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		String header = (itemNumber + 1) + "_IC1";
+		dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		return col;
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		InlineChoiceInteraction choiceInteraction = (InlineChoiceInteraction)interaction;
-		return choiceInteraction.getInlineChoices();
+		
+		List<Identifier> correctAnswers = CorrectResponsesUtil.getCorrectIdentifierResponses(item, interaction);
+		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+		if(StringHelper.containsNonWhitespace(stringuifiedResponse)) {
+			String inlineResponse = CorrectResponsesUtil.stripResponse(stringuifiedResponse);
+			Identifier responseIdentifier = Identifier.assumedLegal(inlineResponse);
+		
+			boolean correct = false;
+			for(Identifier correctAnswer:correctAnswers) {
+				if(responseIdentifier.equals(correctAnswer)) {
+					correct = true;
+					break;
+				}
+			}
+			
+			InlineChoice selectedChoice = choiceInteraction.getInlineChoice(responseIdentifier);
+			if(selectedChoice != null) {
+				String value = getTextContent(selectedChoice);
+				if(correct) {
+					dataRow.addCell(col++, value, workbook.getStyles().getCorrectStyle());
+				} else {
+					dataRow.addCell(col++, value);
+				}
+			} else {
+				col++;
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+	
+	private String getTextContent(InlineChoice selectedChoice) {
+		List<TextOrVariable> values = selectedChoice.getTextOrVariables();
+		for(TextOrVariable value:values) {
+			if(value instanceof TextRun) {
+				return ((TextRun)value).getTextContent();
+			}
+		}
+		return selectedChoice.getIdentifier().toString();
 	}
 
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InteractionArchive.java
index ce3e9784852..78ad2c66cd1 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/InteractionArchive.java
@@ -46,7 +46,7 @@ public interface InteractionArchive {
 	 */
 	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook);
 	
-	public int writeHeader2(Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook);
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook);
 	
 	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook);
 
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java
index f157a9a23f5..9c45638a224 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java
@@ -19,6 +19,7 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
 import java.util.Set;
 
 import org.olat.core.util.StringHelper;
@@ -26,6 +27,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.archive.SimpleContentRenderer;
 
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
@@ -49,19 +51,27 @@ public class MatchInteractionArchive extends DefaultInteractionArchive {
 		}
 		MatchInteraction matchInteraction = (MatchInteraction)interaction;
 		int numOfChoices = matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size();
-		if(interaction.getResponseIdentifier().toString().startsWith("KPRIM_")) {
+		if(numOfChoices > 0) {
 			col += (numOfChoices - 1);
 		}
-		return col++;
+		return col;
 	}
 
 	@Override
-	public int writeHeader2(Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		MatchInteraction matchInteraction = (MatchInteraction)interaction;
+
+		boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_");
+		String fix = kprim ? "_KP" : "_K";
+		
 		int numOfChoices = matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size();
-		for(int i=0; i<numOfChoices; i++) {
-			String header = (itemNumber + 1) + "_K" + i;
-			dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		if(numOfChoices > 0) {
+			for(int i=0; i<numOfChoices; i++) {
+				String header = (itemNumber + 1) + fix + (i + 1);
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
 		}
 		return col;
 	}
@@ -73,36 +83,78 @@ public class MatchInteractionArchive extends DefaultInteractionArchive {
 		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
 		if(!StringHelper.containsNonWhitespace(stringuifiedResponse)) {
 			col += matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size();
-		} else if(matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_")) {
-			Set<String> rightResponses = CorrectResponsesUtil.getCorrectKPrimResponses(item, matchInteraction);
-			SimpleMatchSet fourMatchSet = matchInteraction.getSimpleMatchSets().get(0);
-			for(SimpleAssociableChoice choice:fourMatchSet.getSimpleAssociableChoices()) {
+		} else {
+			boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_");
+			
+			Set<String> correctAnswers = CorrectResponsesUtil.getCorrectDirectPairResponses(item, matchInteraction, false);
+			List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+			
+			SimpleMatchSet firstMatchSet = matchInteraction.getSimpleMatchSets().get(0);
+			SimpleMatchSet secondMatchSet = matchInteraction.getSimpleMatchSets().get(1);
+			
+			for(SimpleAssociableChoice choice:firstMatchSet.getSimpleAssociableChoices()) {
 				String choiceIdentifier = choice.getIdentifier().toString();
-				String markerCorrect = "[" + choiceIdentifier + " correct]";
-				String markerWrong = "[" + choiceIdentifier + " wrong]";
-				
-				boolean isCorrectRight = rightResponses.contains(markerCorrect);
-				String rightFlag = isCorrectRight ? markerCorrect : markerWrong;
-				String wrongFlag = isCorrectRight ? markerWrong : markerCorrect;
 				
-				String value = null;
-				if(stringuifiedResponse.contains(markerCorrect)) {
-					value = "+";
-				} else if(stringuifiedResponse.contains(markerWrong)) {
-					value = "-";
-				}
-				
-				if(stringuifiedResponse.indexOf(rightFlag) >= 0) {
-					dataRow.addCell(col++, value, workbook.getStyles().getCorrectStyle());
-				} else if(stringuifiedResponse.indexOf(wrongFlag) >= 0) {
-					dataRow.addCell(col++, value, null);
+				if(kprim) {
+					String markerCorrect = choiceIdentifier + " correct";
+					String markerWrong = choiceIdentifier + " wrong";
+					
+					boolean isCorrectRight = correctAnswers.contains(markerCorrect);
+					String rightFlag = isCorrectRight ? markerCorrect : markerWrong;
+					String wrongFlag = isCorrectRight ? markerWrong : markerCorrect;
+					
+					String value = null;
+					if(stringuifiedResponse.contains(markerCorrect)) {
+						value = "+";
+					} else if(stringuifiedResponse.contains(markerWrong)) {
+						value = "-";
+					}
+					
+					if(stringuifiedResponse.indexOf(rightFlag) >= 0) {
+						dataRow.addCell(col++, value, workbook.getStyles().getCorrectStyle());
+					} else if(stringuifiedResponse.indexOf(wrongFlag) >= 0) {
+						dataRow.addCell(col++, value, null);
+					} else {
+						col++;
+					}
 				} else {
-					col++;
+					String aResponse = null;
+					for(String r:responses) {
+						if(r.startsWith(choiceIdentifier)) {
+							aResponse = r;
+						}
+					}
+					
+					if(StringHelper.containsNonWhitespace(aResponse)) {
+						boolean correct = correctAnswers.contains(aResponse);
+						
+						String value = null;
+						for(SimpleAssociableChoice association:secondMatchSet.getSimpleAssociableChoices()) {
+							if(aResponse.endsWith(association.getIdentifier().toString())) {
+								value = getContent(association);
+								break;
+							}
+						}
+						
+						if(correct) {
+							dataRow.addCell(col++, value, workbook.getStyles().getCorrectStyle());
+						} else {
+							dataRow.addCell(col++, value, null);
+						}
+					} else {
+						col++;
+					}
 				}
 			}
-		} else {
-			col += matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size();
 		}
 		return col;
 	}
+	
+	private String getContent(SimpleAssociableChoice association) {
+		String content = SimpleContentRenderer.renderFlowStatics(association.getFlowStatics());
+		if(StringHelper.containsNonWhitespace(content)) {
+			return content;
+		}
+		return association.getIdentifier().toString();
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/NoOutputInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/NoOutputInteractionArchive.java
new file mode 100644
index 00000000000..c70a2eeb6b5
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/NoOutputInteractionArchive.java
@@ -0,0 +1,53 @@
+/**
+ * <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.manager.archive.interactions;
+
+import org.olat.core.util.openxml.OpenXMLWorkbook;
+import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
+import org.olat.ims.qti21.AssessmentResponse;
+
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+
+/**
+ * 
+ * Doesn't make any cells
+ * 
+ * Initial date: 27.04.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class NoOutputInteractionArchive implements InteractionArchive  {
+
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		return col;
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		return col;
+	}
+}
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/OrderInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/OrderInteractionArchive.java
index 0d19e6a5dff..ebfae530e98 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/OrderInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/OrderInteractionArchive.java
@@ -19,6 +19,21 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
+
+import org.olat.core.util.StringHelper;
+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.archive.SimpleContentRenderer;
+
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.OrderInteraction;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleChoice;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
+
 /**
  * 
  * Initial date: 27.04.2016<br>
@@ -27,4 +42,78 @@ package org.olat.ims.qti21.manager.archive.interactions;
  */
 public class OrderInteractionArchive extends DefaultInteractionArchive {
 
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
+		
+		OrderInteraction orderInteraction = (OrderInteraction)interaction;
+		int numOfChoices = orderInteraction.getSimpleChoices().size();
+		col += Math.max(1, numOfChoices);
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		OrderInteraction orderInteraction = (OrderInteraction)interaction;
+		int numOfChoices = orderInteraction.getSimpleChoices().size();
+		if(numOfChoices > 0) {
+			for(int i=0; i<numOfChoices; i++) {
+				String header = (itemNumber + 1) + "_O" + (i + 1);
+				dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
+			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		OrderInteraction orderInteraction = (OrderInteraction)interaction;
+		List<SimpleChoice> choices = orderInteraction.getSimpleChoices();
+		
+		if(choices.size() > 0) {
+			String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+			List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+			List<Identifier> correctAnswers = CorrectResponsesUtil.getCorrectOrderedIdentifierResponses(item, interaction);
+			
+			for(int i=0; i<choices.size(); i++) {
+				String currentResponse = null;
+				String currentResponseText = null;
+				if(responses.size() > i) {
+					currentResponse = currentResponseText = responses.get(i);
+					SimpleChoice selectedChoice = orderInteraction.getSimpleChoice(Identifier.assumedLegal(currentResponse));
+					if(selectedChoice != null) {
+						currentResponseText = getContent(selectedChoice);
+					}
+				}
+				
+				String correctAnswer = null;
+				if(correctAnswers.size() > i) {
+					correctAnswer = correctAnswers.get(i).toString();
+				}
+				
+				if(correctAnswer != null && correctAnswer.equals(currentResponse)) {
+					dataRow.addCell(col++, currentResponseText, workbook.getStyles().getCorrectStyle());
+				} else {
+					dataRow.addCell(col++, currentResponseText, null);
+				}
+			}
+		} else {
+			col++;
+		}
+		return col;
+	}
+	
+	private String getContent(SimpleChoice choice) {
+		String content = SimpleContentRenderer.renderFlowStatics(choice.getFlowStatics());
+		if(StringHelper.containsNonWhitespace(content)) {
+			return content;
+		}
+		return choice.getIdentifier().toString();
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/PositionObjectInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/PositionObjectInteractionArchive.java
index 1cf8106e620..4fe2e398276 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/PositionObjectInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/PositionObjectInteractionArchive.java
@@ -39,6 +39,8 @@ public class PositionObjectInteractionArchive extends DefaultInteractionArchive
 	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
 			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		PositionObjectInteraction positionInteraction = (PositionObjectInteraction)interaction;
+		
+		
 		return super.writeInteractionData(item, response, positionInteraction, itemNumber, dataRow, col, workbook);
 	}
 
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SelectPointInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SelectPointInteractionArchive.java
index 6350d28eb21..17d4b888a7d 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SelectPointInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SelectPointInteractionArchive.java
@@ -19,13 +19,21 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 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 uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
-import uk.ac.ed.ph.jqtiplus.node.item.interaction.SelectPointInteraction;
+import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.AreaMapEntry;
+import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.AreaMapping;
+import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
+import uk.ac.ed.ph.jqtiplus.value.PointValue;
 
 /**
  * 
@@ -36,11 +44,83 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.SelectPointInteraction;
 public class SelectPointInteractionArchive extends DefaultInteractionArchive {
 
 	@Override
-	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
-			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
-		SelectPointInteraction selectInteraction = (SelectPointInteraction)interaction;
-		return super.writeInteractionData(item, response, selectInteraction, itemNumber, dataRow, col, workbook);
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		} else {
+			col++;
+		}
+		List<AreaMapEntry> areaMapEntries = getAreaMapEntries(item, interaction);
+		if(areaMapEntries.size() > 0) {
+			col += (areaMapEntries.size() - 1);
+		}
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		List<AreaMapEntry> areaMapEntries = getAreaMapEntries(item, interaction);
+		if(areaMapEntries.size() == 0) {
+			col++;
+		} else {
+			for(AreaMapEntry areaMapEntry:areaMapEntries) {
+				dataRow.addCell(col++, areaMapEntry.getShape().toQtiString());
+			}
+		}
+		return col;
 	}
-	
 
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction, int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		List<AreaMapEntry> areaMapEntries = getAreaMapEntries(item, interaction);
+		if(areaMapEntries.size() == 0) {
+			col++;
+		} else {
+			String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+			List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse);
+			List<PointValue> responsePoints =  CorrectResponsesUtil.parseResponses(responses);
+			
+			List<Integer> freeSlots = new ArrayList<>();
+			for(AreaMapEntry areaMapEntry:areaMapEntries) {
+				int[] coords = CorrectResponsesUtil.convertCoordinates(areaMapEntry.getCoordinates());
+				
+				PointValue foundPoints = null;
+				for(PointValue responsePoint:responsePoints) {
+					if(areaMapEntry.getShape().isInside(coords, responsePoint)) {
+						foundPoints = responsePoint;
+						responsePoints.remove(responsePoint);
+						break;
+					}
+				}
+				
+				if(foundPoints != null) {
+					dataRow.addCell(col++, foundPoints.toQtiString(), workbook.getStyles().getCorrectStyle());
+				} else {
+					freeSlots.add(new Integer(col));
+					dataRow.addCell(col++, "", null);
+				}
+			}
+			
+			//fill the rest
+			for(PointValue responsePoint: responsePoints) {
+				if(freeSlots.size() > 0) {
+					Integer slot = freeSlots.get(0);
+					dataRow.addCell(slot, responsePoint.toQtiString(), null);
+				}
+			}
+		}
+		return col++;
+	}
+	
+	private List<AreaMapEntry> getAreaMapEntries(AssessmentItem item, Interaction interaction) {
+		ResponseDeclaration responseDeclaration = item.getResponseDeclaration(interaction.getResponseIdentifier());
+		if(responseDeclaration != null && responseDeclaration.getAreaMapping() != null) {
+			AreaMapping mapping = responseDeclaration.getAreaMapping();
+			if(mapping != null) {
+				return mapping.getAreaMapEntries();
+			}
+		}
+		return Collections.emptyList();
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SliderInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SliderInteractionArchive.java
index ca09af9bda6..2d356f1f347 100644
--- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SliderInteractionArchive.java
+++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/SliderInteractionArchive.java
@@ -19,6 +19,17 @@
  */
 package org.olat.ims.qti21.manager.archive.interactions;
 
+import java.util.List;
+
+import org.olat.core.util.StringHelper;
+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 uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+
 /**
  * 
  * Initial date: 27.04.2016<br>
@@ -26,5 +37,48 @@ package org.olat.ims.qti21.manager.archive.interactions;
  *
  */
 public class SliderInteractionArchive extends DefaultInteractionArchive {
+	
+	@Override
+	public int writeHeader1(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		if(interactionNumber == 0) {
+			String header = item.getTitle();
+			dataRow.addCell(col, header, workbook.getStyles().getHeaderStyle());
+		}
 
+		col += 1;
+		return col;
+	}
+
+	@Override
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		String header = (itemNumber + 1) + "_SL1";
+		dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
+		return col;
+	}
+
+	@Override
+	public int writeInteractionData(AssessmentItem item, AssessmentResponse response, Interaction interaction,
+			int itemNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+		
+		List<Integer> correctAnswers = CorrectResponsesUtil.getCorrectIntegerResponses(item, interaction);
+		String stringuifiedResponse = response == null ? null : response.getStringuifiedResponse();
+		Integer selectedResponse = null;
+		if(StringHelper.containsNonWhitespace(stringuifiedResponse)) {
+			try {
+				selectedResponse = Integer.parseInt(CorrectResponsesUtil.stripResponse(stringuifiedResponse));
+			} catch (NumberFormatException e) {
+				//parsing can be a problem
+			}
+		}
+		
+		if(selectedResponse == null) {
+			col++;
+		} else if(correctAnswers.contains(selectedResponse)) {
+			dataRow.addCell(col++, selectedResponse, workbook.getStyles().getCorrectStyle());
+		} else {
+			dataRow.addCell(col++, selectedResponse, null);
+		}
+		return col;
+	}
 }
+
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 b263a968716..b602bae321f 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
@@ -39,7 +39,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.TextEntryInteraction;
 public class TextEntryInteractionArchive extends DefaultInteractionArchive {
 
 	@Override
-	public int writeHeader2(Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
+	public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) {
 		String header = (itemNumber + 1) + "_FIB" + (interactionNumber + 1);
 		dataRow.addCell(col++, header, workbook.getStyles().getHeaderStyle());
 		return col;
diff --git a/src/test/java/org/olat/ims/qti21/manager/CorrectResponsesUtilTest.java b/src/test/java/org/olat/ims/qti21/manager/CorrectResponsesUtilTest.java
new file mode 100644
index 00000000000..f046f79c27d
--- /dev/null
+++ b/src/test/java/org/olat/ims/qti21/manager/CorrectResponsesUtilTest.java
@@ -0,0 +1,47 @@
+/**
+ * <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.manager;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * 
+ * Initial date: 27.04.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CorrectResponsesUtilTest {
+	
+	@Test
+	public void parseResponses() {
+		String stringuifiedResponses = "[20 30][test][]";
+		List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponses);
+		
+		Assert.assertNotNull(responses);
+		Assert.assertEquals(3, responses.size());
+		Assert.assertEquals("20 30", responses.get(0));
+		Assert.assertEquals("test", responses.get(1));
+		Assert.assertEquals("", responses.get(2));
+	}
+
+}
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index f10df1d776d..90dc7b66a5a 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -176,6 +176,7 @@ import org.junit.runners.Suite;
 	org.olat.ims.qti.statistics.manager.StatisticsTest.class,
 	org.olat.ims.qti21.manager.AssessmentTestSessionDAOTest.class,
 	org.olat.ims.qti21.manager.AssessmentResponseDAOTest.class,
+	org.olat.ims.qti21.manager.CorrectResponsesUtilTest.class,
 	org.olat.ims.lti.LTIManagerTest.class,
 	org.olat.modules.webFeed.FeedManagerImplTest.class,
 	org.olat.modules.qpool.manager.MetadataConverterHelperTest.class,
-- 
GitLab