Index: trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoder.java
===================================================================
--- trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoder.java	(revision 1327)
+++ trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoder.java	(revision 1333)
@@ -29,4 +29,5 @@
 import de.ugoe.cs.autoquest.eventcore.IEventType;
 import de.ugoe.cs.autoquest.eventcore.StringEventType;
+import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
 import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
@@ -103,4 +104,12 @@
         correctTargets(taskInstanceList);
         
+        // validate the instance list
+        try {
+            new TaskTreeValidator().validate(taskInstanceList);
+        }
+        catch (java.lang.AssertionError e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+        
         return taskInstanceList;
     }
@@ -226,12 +235,4 @@
         }
 
-        // validate the instance
-        try {
-            new TaskTreeValidator().validate(instance);
-        }
-        catch (java.lang.AssertionError e) {
-            throw new IllegalArgumentException(e.getMessage(), e);
-        }
-        
         return instance;
     }
@@ -318,4 +319,18 @@
             }
         }
+        else if ("Optional".equals(type)) {
+            // update the optional with what is optional if available
+            if (children.size() == 1) {
+                ITask newChildTask = children.get(0).getTask();
+                
+                if (((IOptional) task).getMarkedTask() == null) {
+                    taskBuilder.setMarkedTask((IOptional) task, newChildTask);
+                }
+                else if (!((IOptional) task).getMarkedTask().equals(newChildTask)) {
+                    throw new IllegalArgumentException("all children of the same optional must " +
+                                                       "be of an identical task model.");
+                }
+            }
+        }
 
         return task;
@@ -349,7 +364,31 @@
      * @return
      */
-    private IEventType determineType(String type, String enteredText) {
+    private IEventType determineType(String type, String additionalInfo) {
         if ("TextInput".equals(type)) {
-            return new TextInput(enteredText, new ArrayList<Event>());
+            return new TextInput(additionalInfo, new ArrayList<Event>());
+        }
+        else if ("Scroll".equals(type)) {
+            int x = 0;
+            int y = 0;
+            if (additionalInfo != null) {
+                String[] parts = additionalInfo.split(" ");
+                if (parts.length > 0) {
+                    try {
+                        x = Integer.parseInt(parts[0]);
+                    }
+                    catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("could not parse scroll coordinates", e);
+                    }
+                }
+                if (parts.length > 1) {
+                    try {
+                        y = Integer.parseInt(parts[1]);
+                    }
+                    catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("could not parse scroll coordinates", e);
+                    }
+                }
+            }
+            return new Scroll(x, y);
         }
         else {
@@ -428,5 +467,7 @@
         else if (instance instanceof IOptionalInstance) {
             IOptionalInstance optInst = (IOptionalInstance) instance;
-            taskBuilder.setChild(optInst, replaceTargets(optInst.getChild(), replacements));
+            if (optInst.getChild() != null) {
+                taskBuilder.setChild(optInst, replaceTargets(optInst.getChild(), replacements));
+            }
         }
         else if ((instance instanceof IEventTaskInstance) &&
Index: trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeValidator.java
===================================================================
--- trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeValidator.java	(revision 1327)
+++ trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeValidator.java	(revision 1333)
@@ -126,9 +126,8 @@
                         childTask instanceof IOptional);
             
-            assertNotNull("number of children of optional instance must be 1",
-                          ((IOptionalInstance) taskInstance).getChild());
-            
-            assertEquals("task of optional child does not match optional model",
-                         childTask, ((IOptionalInstance) taskInstance).getChild().getTask());
+            if (((IOptionalInstance) taskInstance).getChild() != null) {
+                assertEquals("task of optional child does not match optional model",
+                             childTask, ((IOptionalInstance) taskInstance).getChild().getTask());
+            }
         }
         else if (taskInstance.getTask() instanceof IEventTask) {
@@ -151,5 +150,7 @@
         }
         else if (taskInstance instanceof IOptionalInstance) {
-            validate(((IOptionalInstance) taskInstance).getChild());
+            if (((IOptionalInstance) taskInstance).getChild() != null) {
+                validate(((IOptionalInstance) taskInstance).getChild());
+            }
         }
     }
Index: trunk/autoquest-test-utils/src/test/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoderTest.java
===================================================================
--- trunk/autoquest-test-utils/src/test/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoderTest.java	(revision 1327)
+++ trunk/autoquest-test-utils/src/test/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoderTest.java	(revision 1333)
@@ -20,4 +20,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.ITextArea;
@@ -249,4 +250,111 @@
      */
     @Test
+    public void test_Scroll_01() {
+        String blub =
+            "UserSession {" +
+            "  Scroll body1 { }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+        
+        ITaskInstanceList list = decoder.decode(blub);
+        
+        assertTrue(list.get(0) instanceof IEventTaskInstance);
+        assertTrue(list.get(0).getTask() instanceof IEventTask);
+        
+        assertTrue(((IEventTaskInstance) list.get(0)).getEvent().getType() instanceof Scroll);
+        
+        new TaskTreeValidator().validate(list);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void test_Scroll_02() {
+        String blub =
+            "UserSession {" +
+            "  Scroll body1 { }" +
+            "  Scroll body2 { }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+        
+        ITaskInstanceList list = decoder.decode(blub);
+        
+        assertTrue(list.get(0) instanceof IEventTaskInstance);
+        assertTrue(list.get(0).getTask() instanceof IEventTask);
+        assertTrue(((IEventTaskInstance) list.get(0)).getEvent().getType() instanceof Scroll);
+
+        assertTrue(list.get(1) instanceof IEventTaskInstance);
+        assertTrue(list.get(1).getTask() instanceof IEventTask);
+        assertTrue(((IEventTaskInstance) list.get(1)).getEvent().getType() instanceof Scroll);
+        
+        assertFalse(list.get(0).equals(list.get(1)));
+        assertFalse(list.get(0).getTask().equals(list.get(1).getTask()));
+        
+        new TaskTreeValidator().validate(list);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void test_Scroll_03() {
+        String blub =
+            "UserSession {" +
+            "  Scroll body1 { }" +
+            "  Scroll body1 { }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+        
+        ITaskInstanceList list = decoder.decode(blub);
+        
+        assertTrue(list.get(0) instanceof IEventTaskInstance);
+        assertTrue(list.get(0).getTask() instanceof IEventTask);
+        assertTrue(((IEventTaskInstance) list.get(0)).getEvent().getType() instanceof Scroll);
+
+        assertTrue(list.get(1) instanceof IEventTaskInstance);
+        assertTrue(list.get(1).getTask() instanceof IEventTask);
+        assertTrue(((IEventTaskInstance) list.get(1)).getEvent().getType() instanceof Scroll);
+        
+        assertFalse(list.get(0).equals(list.get(1)));
+        assertTrue(list.get(0).getTask().equals(list.get(1).getTask()));
+        
+        new TaskTreeValidator().validate(list);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void test_Scroll_04() {
+        String blub =
+            "UserSession {" +
+            "  Scroll body1 (1 2) { }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+        
+        ITaskInstanceList list = decoder.decode(blub);
+        
+        assertTrue(list.get(0) instanceof IEventTaskInstance);
+        assertTrue(list.get(0).getTask() instanceof IEventTask);
+        
+        assertTrue(((IEventTaskInstance) list.get(0)).getEvent().getType() instanceof Scroll);
+        
+        Scroll scroll = (Scroll) ((IEventTaskInstance) list.get(0)).getEvent().getType();
+        
+        assertEquals(1, scroll.getXPosition());
+        assertEquals(2, scroll.getYPosition());
+        
+        new TaskTreeValidator().validate(list);
+    }
+
+    /**
+     *
+     */
+    @Test
     public void test_GuiElements_01() {
         String blub =
@@ -1054,3 +1162,79 @@
         decoder.decode(blub);
     }
+
+    /**
+     *
+     */
+    @Test
+    public void test_Optional_07() {
+        String blub =
+            "UserSession {" +
+            "  Optional op1 {" +
+            "    MouseClick c1 { }" +
+            "  }" +
+            "  Optional op1 { }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+
+        ITaskInstanceList list = decoder.decode(blub);
+
+        assertTrue(list.get(0) instanceof IOptionalInstance);
+        assertNotNull(((IOptionalInstance) list.get(0)).getChild());
+        assertTrue(((IOptionalInstance) list.get(0)).getChild() instanceof IEventTaskInstance);
+
+        assertTrue(list.get(0).getTask() instanceof IOptional);
+        assertNotNull(((IOptional) list.get(0).getTask()).getMarkedTask());
+        assertTrue(((IOptional) list.get(0).getTask()).getMarkedTask() instanceof IEventTask);
+
+        assertTrue(list.get(1) instanceof IOptionalInstance);
+        assertNull(((IOptionalInstance) list.get(1)).getChild());
+
+        assertTrue(list.get(1).getTask() instanceof IOptional);
+        assertNotNull(((IOptional) list.get(1).getTask()).getMarkedTask());
+        assertTrue(((IOptional) list.get(1).getTask()).getMarkedTask() instanceof IEventTask);
+
+        assertFalse(list.get(0).equals(list.get(1)));
+        assertTrue(list.get(0).getTask().equals(list.get(1).getTask()));
+        
+        new TaskTreeValidator().validate(list);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void test_Optional_08() {
+        String blub =
+            "UserSession {" +
+            "  Optional op1 { }" +
+            "  Optional op1 {" +
+            "    MouseClick c1 { }" +
+            "  }" +
+            "}";
+
+        TaskTreeDecoder decoder = new TaskTreeDecoder(new TaskFactory(), new TaskBuilder());
+
+        ITaskInstanceList list = decoder.decode(blub);
+
+        assertTrue(list.get(0) instanceof IOptionalInstance);
+        assertNull(((IOptionalInstance) list.get(0)).getChild());
+
+        assertTrue(list.get(0).getTask() instanceof IOptional);
+        assertNotNull(((IOptional) list.get(0).getTask()).getMarkedTask());
+        assertTrue(((IOptional) list.get(0).getTask()).getMarkedTask() instanceof IEventTask);
+
+        assertTrue(list.get(1) instanceof IOptionalInstance);
+        assertNotNull(((IOptionalInstance) list.get(1)).getChild());
+        assertTrue(((IOptionalInstance) list.get(1)).getChild() instanceof IEventTaskInstance);
+
+        assertTrue(list.get(1).getTask() instanceof IOptional);
+        assertNotNull(((IOptional) list.get(1).getTask()).getMarkedTask());
+        assertTrue(((IOptional) list.get(1).getTask()).getMarkedTask() instanceof IEventTask);
+
+        assertFalse(list.get(0).equals(list.get(1)));
+        assertTrue(list.get(0).getTask().equals(list.get(1).getTask()));
+        
+        new TaskTreeValidator().validate(list);
+    }
 }
