diff --git a/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java b/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
index e04d332af362cb77057e23bf7cc307cd8a87ecab..f75e796ef3223d880b40bf61c9d01742a8ab58ef 100644
--- a/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
+++ b/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
@@ -124,14 +124,11 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 	public SubscriptionContext getAssessmentSubscriptionContext(Identity ident, ICourse course) {
 		SubscriptionContext sctx = null;
 		if (ident == null || canSubscribeForAssessmentNotification(ident, course)) {
-			// Creates a new SubscriptionContext only if not found into cache
-			if (sctx == null) {
-				// a subscription context showing to the root node (the course's root
-				// node is started when clicking such a notification)
-				CourseNode cn = course.getRunStructure().getRootNode();
-				Long resourceableId = course.getResourceableId();
-				sctx = new SubscriptionContext(CourseModule.ORES_COURSE_ASSESSMENT, resourceableId, cn.getIdent());
-			}
+			// a subscription context showing to the root node (the course's root
+			// node is started when clicking such a notification)
+			CourseNode cn = course.getRunStructure().getRootNode();
+			Long resourceableId = course.getResourceableId();
+			sctx = new SubscriptionContext(CourseModule.ORES_COURSE_ASSESSMENT, resourceableId, cn.getIdent());
 		}
 		return sctx;
 	}
@@ -310,14 +307,13 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 			// exceptions, course
 			// can't be loaded when already deleted
 			if (notificationsManager.isPublisherValid(p) && compareDate.before(latestNews)) {
-				Long courseId = new Long(p.getData());
+				Long courseId = Long.valueOf(p.getData());
 				final ICourse course = loadCourseFromId(courseId);
 				if (courseStatus(course)) {
 					// course admins or users with the course right to have full access to
 					// the assessment tool will have full access to user tests
 					CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
-					final boolean hasFullAccess = (cgm.isIdentityCourseAdministrator(identity) ? true : cgm.hasRight(identity,
-							CourseRights.RIGHT_ASSESSMENT));
+					final boolean hasFullAccess = cgm.isIdentityCourseAdministrator(identity) || cgm.hasRight(identity, CourseRights.RIGHT_ASSESSMENT);
 					final Set<Identity> coachedUsers = new HashSet<>();
 					if (!hasFullAccess) {
 						// initialize list of users, only when user has not full access
diff --git a/src/main/java/org/olat/modules/scorm/OLATApiAdapter.java b/src/main/java/org/olat/modules/scorm/OLATApiAdapter.java
index 3b2502cf0b3d9304288fa174b305106da97825be..3f27abb8415c47715beca49af360fd8facc65e8d 100644
--- a/src/main/java/org/olat/modules/scorm/OLATApiAdapter.java
+++ b/src/main/java/org/olat/modules/scorm/OLATApiAdapter.java
@@ -44,7 +44,6 @@ import java.util.Set;
 
 import org.olat.core.logging.LogDelegator;
 import org.olat.core.logging.OLATRuntimeException;
-import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.modules.scorm.manager.ScormManager;
 import org.olat.modules.scorm.server.beans.LMSDataFormBean;
@@ -63,10 +62,9 @@ import ch.ethz.pfplms.scorm.api.ApiAdapter;
  * @author guido
  */
 public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm.api.ApiAdapterInterface {
-	private final	ApiAdapter core; 
-	//private ScormTrackingManager scormTracking;
-	
-	private Hashtable<String,String> olatScoCmi = new Hashtable<String,String>();
+	private final ApiAdapter core; 
+
+	private Hashtable<String,String> olatScoCmi = new Hashtable<>();
 
 	private String  olatStudentId;
 	private String  olatStudentName;
@@ -81,7 +79,7 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 	private LMSDataHandler odatahandler;
 	private ScormManager scormManager;
 	private SettingsHandlerImpl scormSettingsHandler;
-	private final List<ScormAPICallback> apiCallbacks = new ArrayList<ScormAPICallback>(2);
+	private final List<ScormAPICallback> apiCallbacks = new ArrayList<>(2);
 	// 
 	private Properties scoresProp; // keys: sahsId; values = raw score of an sco
 	private Properties lessonStatusProp;
@@ -126,31 +124,21 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 		scorePropsFile = new File(savePath, "_olat_score.properties");
 		scoresProp = new Properties();
 		if (scorePropsFile.exists()) {
-			InputStream is = null;
-			try {
-				is = new BufferedInputStream(new FileInputStream(scorePropsFile));
+			try(InputStream is = new BufferedInputStream(new FileInputStream(scorePropsFile))) {
 				scoresProp.load(is);
 			} catch (IOException e) {
 				throw e;
 			}
-			finally {
-				if (is != null) FileUtils.closeSafely(is);
-			}
 		}
 		
 		lessonStatusPropsFile = new File(savePath, "_olat_lesson_status.properties");
 		lessonStatusProp = new Properties();
 		if (lessonStatusPropsFile.exists()) {
-			InputStream is = null;
-			try {
-				is = new BufferedInputStream(new FileInputStream(lessonStatusPropsFile));
+			try(InputStream is = new BufferedInputStream(new FileInputStream(lessonStatusPropsFile))) {
 				lessonStatusProp.load(is);
 			} catch (IOException e) {
 				throw e;
 			}
-			finally {
-				if (is != null) FileUtils.closeSafely(is);
-			}
 		}
 		
 		scormManager = new ScormManager(cpRoot.getAbsolutePath(), true, true, true, scormSettingsHandler);
@@ -274,12 +262,10 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 		
 		LMSDataFormBean lmsDataBean = new LMSDataFormBean();
 		lmsDataBean.setItemID(olatScoId);
-		//TODO:gs pass the dataBean for use, and do not get it a second time
 		lmsDataBean.setNextAction("5");
 		lmsDataBean.setLmsAction("update");
-		Map <String,String>cmiData = new HashMap<String,String>();
+		Map <String,String>cmiData = new HashMap<>();
 		
-		//TODO:gs:c make it possible only to update the changed cmi data.
 		if (ins.size() > 0){
 			Set <String> set = ins.keySet();
 			for(Iterator<String> it = set.iterator();it.hasNext();){
@@ -320,30 +306,20 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 				synchronized(this) { //o_clusterOK by:fj: instance is spawned by the ScormAPIandDisplayController
 					if(StringHelper.containsNonWhitespace(rawScore)) {
 						scoresProp.put(olatScoId, rawScore);
-						OutputStream os = null;
-						try {
-							os = new BufferedOutputStream(new FileOutputStream(scorePropsFile));
+						try(OutputStream os = new BufferedOutputStream(new FileOutputStream(scorePropsFile))) {
 							scoresProp.store(os, null);
 						} catch (IOException e) {
 							throw new OLATRuntimeException(this.getClass(), "could not save scorm-properties-file: "+scorePropsFile.getAbsolutePath(), e);
 						}
-						finally {
-							FileUtils.closeSafely(os);
-						}
 					}
 
 					if(StringHelper.containsNonWhitespace(lessonStatus)) {
 						lessonStatusProp.put(olatScoId, lessonStatus);
-						OutputStream os = null;
-						try {
-							os = new BufferedOutputStream(new FileOutputStream(lessonStatusPropsFile));
+						try(OutputStream os = new BufferedOutputStream(new FileOutputStream(lessonStatusPropsFile))) {
 							lessonStatusProp.store(os, null);
 						} catch (IOException e) {
 							throw new OLATRuntimeException(this.getClass(), "could not save scorm-properties-file: "+scorePropsFile.getAbsolutePath(), e);
 						}
-						finally {
-							FileUtils.closeSafely(os);
-						}
 					}
 					// notify
 					if (!apiCallbacks.isEmpty()) {
@@ -421,7 +397,6 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 	 * @return true if the item is completed
 	 */
 	public boolean isItemCompleted(String itemId){
-		//TODO:gs make method faster by caching lmsBean, but when to set out of date?
 		LMSDataFormBean lmsDataBean = new LMSDataFormBean();
 		lmsDataBean.setItemID(itemId);
 		lmsDataBean.setLmsAction("get");
@@ -435,7 +410,6 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 	 * @return true if item has any not fullfilled preconditions
 	 */
 	public boolean hasItemPrerequisites(String itemId) {
-		//TODO:gs make method faster by caching lmsBean, but when to set out of date?
 		LMSDataFormBean lmsDataBean = new LMSDataFormBean();
 		lmsDataBean.setItemID(itemId);
 		lmsDataBean.setLmsAction("get");
@@ -453,7 +427,7 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 		odatahandler = new LMSDataHandler(scormManager, lmsDataBean, scormSettingsHandler);
 		LMSResultsBean lmsBean = odatahandler.getResultsBean();
 		String[][] preReqTbl = lmsBean.getPreReqTable();
-		Map <String,String>itemsStatus = new HashMap<String,String>();
+		Map <String,String>itemsStatus = new HashMap<>();
 		//put table into map 
 		for(int i=0; i < preReqTbl.length; i++){
 			if(preReqTbl[i][1].equals("not attempted")) preReqTbl[i][1] ="not_attempted";
@@ -467,7 +441,6 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 	 * @return the previos Sco itemId
 	 */
 	public Integer getPreviousSco(String recentId) {
-		//		TODO:gs make method faster by caching lmsBean, but when to set out of date?
 		LMSDataFormBean lmsDataBean = new LMSDataFormBean();
 		lmsDataBean.setItemID(recentId);
 		lmsDataBean.setLmsAction("get");
@@ -481,7 +454,7 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 				break;
 			}
 		}
-		return new Integer(previousNavScoId);
+		return Integer.valueOf(previousNavScoId);
 	}
 
 	/**
@@ -489,7 +462,6 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 	 * @return the next Sco itemId
 	 */
 	public Integer getNextSco(String recentId) {
-		//		TODO:gs make method faster by chaching lmsBean, but when to set out of date?
 		LMSDataFormBean lmsDataBean = new LMSDataFormBean();
 		lmsDataBean.setItemID(recentId);
 		lmsDataBean.setLmsAction("get");
@@ -503,7 +475,7 @@ public	class OLATApiAdapter extends LogDelegator implements ch.ethz.pfplms.scorm
 				break;
 			}
 		}
-		return new Integer(nextNavScoId);
+		return Integer.valueOf(nextNavScoId);
 	}
 	
 	/****************************************************************************************
diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
index 3a41494cb6fde67267eee3e222319df64a749b79..b8a4bf6e6dba72addd8f3928993d9b336c5ad6b2 100644
--- a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
+++ b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
@@ -49,6 +49,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.nodes.ScormCourseNode;
 import org.olat.course.nodes.scorm.ScormEditController;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -199,7 +200,7 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 			if (currentPassed == null || !currentPassed.booleanValue()) {
 				// </OLATEE-27>
 				boolean increment = !attemptsIncremented && finish;
-				ScoreEvaluation sceval = new ScoreEvaluation(new Float(0.0f), Boolean.valueOf(passed));
+				ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(0.0f), Boolean.valueOf(passed));
 				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
 				if(increment) {
 					attemptsIncremented = true;
@@ -214,12 +215,17 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 			}
 		} else {
 			boolean increment = !attemptsIncremented && finish;
-			ScoreEvaluation sceval = new ScoreEvaluation(new Float(0.0f), Boolean.valueOf(passed));
+			ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(0.0f), Boolean.valueOf(passed));
 			scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user);
 			if(increment) {
 				attemptsIncremented = true;
 			}
 		}
+		
+		if(finish) {
+			Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
+			CoreSpringFactory.getImpl(AssessmentNotificationsHandler.class).markPublisherNews(identity, courseId);
+		}
 
 		if (log.isDebug()) {
 			String msg = "for scorm node:" + scormNode.getIdent() + " (" + scormNode.getShortTitle() + ") a lmsCommit for scoId "
@@ -254,7 +260,7 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 			if (score > (currentScore != null ? currentScore : -1f)) {
 				// </OLATEE-27>
 				boolean increment = !attemptsIncremented && finish;
-				ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), Boolean.valueOf(passed));
+				ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), Boolean.valueOf(passed));
 				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
 				if(increment) {
 					attemptsIncremented = true;
@@ -274,12 +280,17 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 			}
 			// </OLATEE-27>
 			boolean increment = !attemptsIncremented && finish;
-			ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), Boolean.valueOf(passed));
+			ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), Boolean.valueOf(passed));
 			scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user);
 			if(increment) {
 				attemptsIncremented = true;
 			}
 		}
+		
+		if(finish) {
+			Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
+			CoreSpringFactory.getImpl(AssessmentNotificationsHandler.class).markPublisherNews(identity, courseId);
+		}
 
 		if (log.isDebug()) {
 			String msg = "for scorm node:" + scormNode.getIdent() + " (" + scormNode.getShortTitle() + ") a lmsCommit for scoId "
diff --git a/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java b/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java
index 78d8a208a10671916881a9b6763e141192ec6b7d..8fb3833883f2e88c0fb24ace3cc2d70c2fe52c6d 100644
--- a/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java
+++ b/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java
@@ -110,7 +110,7 @@ public class ImsQTI21InteractionsTest extends Deployments {
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
 			.answerHotspot("circle")
-			.saveAnswer()
+			.saveGraphicAnswer()
 			.assertFeedback("Correct!")
 			.endTest();
 		//check the results
@@ -153,6 +153,7 @@ public class ImsQTI21InteractionsTest extends Deployments {
 		qtiPage
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
+			.moveToAssociateItems()
 			.answerAssociate("Antonio", 1, true)
 			.answerAssociate("Prospero", 1, false)
 			.answerAssociate("Capulet", 2, true)
@@ -201,6 +202,7 @@ public class ImsQTI21InteractionsTest extends Deployments {
 		qtiPage
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
+			.moveToGraphicAssociateInteraction()
 			.answerGraphicAssociate("B")
 			.answerGraphicAssociate("C")
 			.answerGraphicAssociate("C")
@@ -492,6 +494,7 @@ public class ImsQTI21InteractionsTest extends Deployments {
 		qtiPage
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
+			.moveToGraphicOrderInteraction()
 			.answerGraphicOrderById("A")
 			.answerGraphicOrderById("D")
 			.answerGraphicOrderById("C")
@@ -539,9 +542,10 @@ public class ImsQTI21InteractionsTest extends Deployments {
 		qtiPage
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
-			.answerPositionObject(0, 118, 184)
-			.answerPositionObject(1, 150, 235)
-			.answerPositionObject(2, 96, 114)
+			.moveToPositionObject()
+			.answerPositionObject(0, 118, 184, 4)
+			.answerPositionObject(1, 150, 235, 4)
+			.answerPositionObject(2, 96, 114, 4)
 			.saveAnswer()
 			.endTest()
 			.closeTest();
@@ -629,6 +633,7 @@ public class ImsQTI21InteractionsTest extends Deployments {
 		qtiPage
 			.clickToolbarBack()
 			.assertOnAssessmentItem()
+			.moveToVerticalSlider()
 			.answerVerticalSlider(16)
 			.saveAnswer()
 			.endTest()
diff --git a/src/test/java/org/olat/selenium/page/graphene/Position.java b/src/test/java/org/olat/selenium/page/graphene/Position.java
index fd434f254bad8f5d627c38ff9cf9211f7a83b71c..2582fb253d784ec49e45eae3b3d5ae25269a52d8 100644
--- a/src/test/java/org/olat/selenium/page/graphene/Position.java
+++ b/src/test/java/org/olat/selenium/page/graphene/Position.java
@@ -82,6 +82,16 @@ public class Position {
 		return new Position(x, y);
 	}
 	
+	public static Position valueOf(int x, int y, int firefoxCorrection, Dimension dimension, WebDriver browser) {
+		if(browser instanceof FirefoxDriver) {
+			x = x - Math.round(dimension.getWidth() / 2.0f);
+			y = y - Math.round(dimension.getHeight() / 2.0f);
+			x += firefoxCorrection;
+			y += firefoxCorrection;
+		}
+		return new Position(x, y);
+	}
+	
 	public static Position valueOf(int x, int y, int width, int height, WebDriver browser) {
 		if(browser instanceof FirefoxDriver) {
 			x = x - Math.round(width / 2.0f);
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
index 9e65fdb3712212bfbb79d8ed6d9fb9da31bda60d..6c7df79701663a56338b9556cff5491025ef7ce3 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
@@ -181,6 +181,20 @@ public class QTI21Page {
 		return this;
 	}
 	
+	/**
+	 * Only move if Firefox.
+	 * 
+	 * @return Itself
+	 */
+	public QTI21Page moveToGraphicOrderInteraction() {
+		By imgBy = By.xpath("//div[contains(@class,'graphicOrderInteraction')]");
+		OOGraphene.waitElement(imgBy, browser);
+		if(browser instanceof FirefoxDriver) {
+			OOGraphene.scrollTo(imgBy, browser);
+		}
+		return this;
+	}
+	
 	/**
 	 * Select the area with the specified data-qti-id.
 	 * @param id The id save in data-qti-id
@@ -189,9 +203,20 @@ public class QTI21Page {
 	public QTI21Page answerGraphicOrderById(String id) {
 		OOGraphene.waitElement(By.className("graphicOrderInteraction"), browser);
 		By areaBy = By.xpath("//div[contains(@class,'graphicOrderInteraction')]//map/area[@data-qti-id='" + id + "']");
-		List<WebElement> elements = browser.findElements(areaBy);
-		Assert.assertEquals("Hotspot with data-qti-id " + id, 1, elements.size()); 
-		elements.get(0).click();
+		WebElement areaEl = browser.findElement(areaBy);
+		if(browser instanceof FirefoxDriver) {
+			String coords = areaEl.getAttribute("coords");
+			By imgBy = By.xpath("//div[contains(@class,'graphicOrderInteraction')]/div/img");
+			WebElement element = browser.findElement(imgBy);
+			Dimension dim = element.getSize();
+			Position pos = Position.valueOf(coords, dim, browser);
+			new Actions(browser)
+				.moveToElement(element, pos.getX(), pos.getY())
+				.click()
+				.perform();
+		} else {
+			areaEl.click();
+		}
 		return this;
 	}
 	
@@ -336,25 +361,67 @@ public class QTI21Page {
 		return this;
 	}
 	
+	/**
+	 * Only move if Firefox.
+	 * 
+	 * @return Itself
+	 */
+	public QTI21Page moveToAssociateItems() {
+		By associateItemsBy = By.xpath("//div[@class='association'][3]");
+		OOGraphene.waitElement(associateItemsBy, browser);
+		if(browser instanceof FirefoxDriver) {
+			OOGraphene.scrollTo(associateItemsBy, browser);
+		}
+		return this;
+	}
+	
 	public QTI21Page answerGraphicAssociate(String id) {
 		OOGraphene.waitElement(By.className("graphicAssociateInteraction"), browser);
 		By areaBy = By.xpath("//div[contains(@class,'graphicAssociateInteraction')]//map/area[@data-qti-id='" + id + "']");
-		List<WebElement> elements = browser.findElements(areaBy);
-		Assert.assertEquals("Area by " + id, 1, elements.size()); 
-		elements.get(0).click();
+		WebElement areaEl = browser.findElement(areaBy);
+		if(browser instanceof FirefoxDriver) {
+			String coords = areaEl.getAttribute("coords");
+			By imgBy = By.xpath("//div[contains(@class,'graphicAssociateInteraction')]/div/div/img");
+			WebElement element = browser.findElement(imgBy);
+			Dimension dim = element.getSize();
+			Position pos = Position.valueOf(coords, dim, browser);
+			new Actions(browser)
+				.moveToElement(element, pos.getX(), pos.getY())
+				.click()
+				.perform();
+		} else {
+			areaEl.click();
+		}
+		return this;
+	}
+	
+	/**
+	 * Only move if Firefox.
+	 * 
+	 * @return Itself
+	 */
+	public QTI21Page moveToGraphicAssociateInteraction() {
+		By associateItemsBy = By.xpath("//div[@class='graphicAssociateInteraction']");
+		OOGraphene.waitElement(associateItemsBy, browser);
+		if(browser instanceof FirefoxDriver) {
+			OOGraphene.scrollTo(associateItemsBy, browser);
+		}
 		return this;
 	}
 	
 	public QTI21Page answerOrderDropItem(String source) {
-		By sourceBy = By.xpath("//li[contains(@class,'o_assessmentitem_order_item')][text()[contains(.,'" + source + "')]]");
+		By sourceBy = By.xpath("//li[@class='o_assessmentitem_order_item'][contains(text(),'" + source + "')]");
 		OOGraphene.waitElement(sourceBy, 5, browser);
 		WebElement sourceEl = browser.findElement(sourceBy);
 		By targetBy = By.xpath("//div[@class='orderInteraction']//div[contains(@class,'target')]/ul");
 		WebElement targetEl = browser.findElement(targetBy);
+		
+		Position sourcePos = Position.valueOf(30, 30, sourceEl.getSize(), browser);
+		Position targetPos = Position.valueOf(30, 30,  targetEl.getSize(), browser);
 		new Actions(browser)
-			.moveToElement(sourceEl, 30, 30)
+			.moveToElement(sourceEl, sourcePos.getX(), sourcePos.getY())
 			.clickAndHold()
-			.moveToElement(targetEl, 30, 30)
+			.moveToElement(targetEl, targetPos.getX(), targetPos.getY())
 			.release()
 			.build()
 			.perform();
@@ -389,11 +456,23 @@ public class QTI21Page {
 	public QTI21Page answerGraphicGapClick(String item, String gap) {
 		By sourceBy = By.xpath("//div[contains(@class,'gap_container')]/div[contains(@class,'o_gap_item')][@data-qti-id='" + item + "']");
 		OOGraphene.waitElement(sourceBy, 5, browser);
-		WebElement sourceEl = browser.findElement(sourceBy);
-		sourceEl.click();
-		By targetBy = By.xpath("//div[@class='graphicGapMatchInteraction']//map/area[@data-qti-id='" + gap + "']");
-		WebElement targetEl = browser.findElement(targetBy);
-		targetEl.click();
+		browser.findElement(sourceBy).click();
+		By areaBy = By.xpath("//div[@class='graphicGapMatchInteraction']//map/area[@data-qti-id='" + gap + "']");
+		WebElement areaEl = browser.findElement(areaBy);
+		if(browser instanceof FirefoxDriver) {
+			String coords = areaEl.getAttribute("coords");
+			By imgBy = By.xpath("//div[contains(@class,'graphicGapMatchInteraction')]/div/div/img");
+			WebElement element = browser.findElement(imgBy);
+			Dimension dim = element.getSize();
+			Position pos = Position.valueOf(coords, dim, browser);
+			new Actions(browser)
+				.moveToElement(element, pos.getX(), pos.getY())
+				.click()
+				.perform();
+			
+		} else {
+			areaEl.click();
+		}
 		return this;
 	}
 	
@@ -416,31 +495,63 @@ public class QTI21Page {
 		return this;
 	}
 	
+	/**
+	 * Only move if Firefox.
+	 * 
+	 * @return Itself
+	 */
+	public QTI21Page moveToPositionObject() {
+		By itemBy = By.xpath("//div[contains(@class,'positionObjectStage')]//div[contains(@id,'object-item-')]");
+		OOGraphene.waitElement(itemBy, browser);
+		if(browser instanceof FirefoxDriver) {
+			OOGraphene.scrollTo(itemBy, browser);
+		}
+		return this;
+	}
+	
 	/**
 	 * Select the object by its index (start with 0) and
-	 * move it on the image and the specified coodinates.
+	 * move it on the image and the specified coordinates.
 	 * 
 	 * @param index The index of the object
 	 * @param x The x target coordinate
 	 * @param y The y target coordinate
 	 * @return Itself
 	 */
-	public QTI21Page answerPositionObject(int index, int x, int y) {
+	public QTI21Page answerPositionObject(int index, int x, int y, int firefoxCorrection) {
 		By itemBy = By.xpath("//div[contains(@class,'positionObjectStage')]//div[@id='object-item-" + index + "']");
 		OOGraphene.waitElement(itemBy, browser);
 		WebElement itemEl = browser.findElement(itemBy);
 		By targetBy = By.xpath("//div[@class='positionObjectStage']//img[contains(@id,'qtiworks_id_container_')]");
 		WebElement targetEl = browser.findElement(targetBy);
+		Dimension targetDim = targetEl.getSize();
+		Position targetPos = Position.valueOf(x, y, firefoxCorrection, targetDim, browser);
+		Dimension itemDim = itemEl.getSize();
+		Position itemPos = Position.valueOf(5, 5, itemDim, browser);
 		new Actions(browser)
-			.moveToElement(itemEl, 5, 5)
+			.moveToElement(itemEl, itemPos.getX(), itemPos.getY())
 			.clickAndHold()
-			.moveToElement(targetEl, x, y)
+			.moveToElement(targetEl, targetPos.getX() + 4, targetPos.getY() + 4)
 			.release()
 			.build()
 			.perform();
 		return this;
 	}
 	
+	/**
+	 * Only move if Firefox.
+	 * 
+	 * @return Itself
+	 */
+	public QTI21Page moveToVerticalSlider() {
+		By interactionBy = By.id("itemBody");
+		OOGraphene.waitElement(interactionBy, browser);
+		if(browser instanceof FirefoxDriver) {
+			OOGraphene.scrollTo(interactionBy, browser);
+		}
+		return this;
+	}
+	
 	/**
 	 * Select the point based on coordinates.
 	 * 
@@ -453,15 +564,14 @@ public class QTI21Page {
 		WebElement sliderEl = browser.findElement(sliderBy);
 		Dimension size = sliderEl.getSize();
 		float height = (size.getHeight() / 100f) * val;
-		float scaledY = size.getHeight() - height;
-		
+		int scaledY = Math.round(size.getHeight() - height);
+		Position pos = Position.valueOf(5, scaledY, size, browser);
 		new Actions(browser)
-			.moveToElement(sliderEl, 5, Math.round(scaledY))
+			.moveToElement(sliderEl, pos.getX(), pos.getY())
 			.click()
 			.build()
 			.perform();
 		
-		
 		By valueBy = By.xpath("//div[contains(@class,'sliderInteraction')]/div[contains(@class,'sliderVertical')]/div[contains(@class,'sliderValue')]/span[text()='" + val + "']");
 		OOGraphene.waitElement(valueBy, browser);
 		return this;