Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageQuantileRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageQuantileRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageQuantileRule.java	(revision 1493)
@@ -0,0 +1,89 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class EventCoverageQuantileRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        checkForCooccurrences(results, taskModel);
+
+        return results;
+    }
+
+    /**
+     * 
+     */
+    private void checkForCooccurrences(UsabilityEvaluationResult results, ITaskModel taskModel) {
+        for (ITask task : taskModel.getTasks()) {
+            // only sequences are important for task cooccurrences
+            if (task instanceof ISequence) {
+                ISequence sequence = (ISequence) task;
+                int ratio = taskModel.getTaskInfo(sequence).getMeasureValue
+                    (TaskMetric.EVENT_COVERAGE_QUANTILE);
+
+                //TODO document magic numbers
+                UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                    (ratio, 990, 975, 950, 900, sequence, taskModel);
+
+                if (severity != null) {
+                    
+                    double effRatio = 0;
+                    
+                    if (ratio >= 990) {
+                        effRatio = 1;
+                    }
+                    else if (ratio >= 975) {
+                        effRatio = 2.5;
+                    }
+                    else if (ratio >= 950) {
+                        effRatio = 5;
+                    }
+                    else if (ratio >= 900) {
+                        effRatio = 10;
+                    }
+                    
+                    Map<String, Object> parameters = new HashMap<String, Object>();
+                    parameters.put("task", sequence);
+                    parameters.put("ratio", effRatio);
+
+                    results.addDefect(severity, UsabilityDefectDescription.HIGH_EVENT_COVERAGE,
+                                      parameters);
+                }
+            }
+        }
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageRatioRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageRatioRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageRatioRule.java	(revision 1493)
@@ -0,0 +1,73 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class EventCoverageRatioRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        checkForImportantTasks(results, taskModel);
+
+        return results;
+    }
+
+    /**
+     * 
+     */
+    private void checkForImportantTasks(UsabilityEvaluationResult results, ITaskModel taskModel) {
+        for (ITask task : taskModel.getTasks()) {
+            // only sequences are important
+            if (task instanceof ISequence) {
+                ISequence sequence = (ISequence) task;
+                int ratio = taskModel.getTaskInfo(sequence).getMeasureValue
+                    (TaskMetric.EVENT_COVERAGE_RATIO);
+
+                //TODO document magic numbers
+                UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                    (ratio, 300, 150, 50, 10, sequence, taskModel);
+
+                if (severity != null) {
+                    Map<String, Object> parameters = new HashMap<String, Object>();
+                    parameters.put("task", sequence);
+                    parameters.put("ratio", (ratio / 10));
+
+                    results.addDefect(severity, UsabilityDefectDescription.HIGH_EVENT_COVERAGE,
+                                      parameters);
+                }
+            }
+        }
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/MissingFeedbackRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/MissingFeedbackRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/MissingFeedbackRule.java	(revision 1493)
@@ -0,0 +1,298 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class MissingFeedbackRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        Map<ITask, Integer> smellingTasks = getTasksShowingMissingFeedback(taskModel.getTasks());
+        analyzeTasksShowingMissingFeedback(smellingTasks, results, taskModel);
+
+        return results;
+    }
+
+    /**
+     *
+     */
+    private void analyzeTasksShowingMissingFeedback(Map<ITask, Integer>       smellingTasks,
+                                                    UsabilityEvaluationResult results,
+                                                    ITaskModel                taskModel)
+    {
+
+        for (Map.Entry<ITask, Integer> entry : smellingTasks.entrySet()) {
+            // impatience ratio is the sum of the times between two clicks of a user on the
+            // identical (not semantically equal) button. If the user is highly impatient and
+            // clicks the identical button more than two times, the time difference between the
+            // first click and the last click is multiplied with the number of additional clicks
+            // to give such behavior a higher weight. The average impatience ratio is the
+            // cumulative impatience of all task instances divided by the number of task
+            // instances. I.e. if all users show impatience, i.e., all instances have an impatience
+            // ratio, the average impatience of a task is relatively high. Else, it is rather low.
+            // If, e.g., all users clicked the identical button again in between 3 seconds, the
+            // average impatience of the task would be 3000, which should be a usability smell.
+            // If the users click even more often on the identical button, the ratio is even higher.
+            // If only one of 50 users clicked twice, than the ratio is only 60, which should not
+            // be considered as usability smell.
+            
+            UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                (entry.getValue(), 2000, 1000, 500, 50, entry.getKey(), taskModel);
+
+            if (severity != null) {
+                Map<String, Object> parameters = new HashMap<String, Object>();
+
+                int allClickCount = 0;
+                int multipleClickCount = 0;
+                long cummulatedWaitingTime = 0;
+                int numberOfAdditionalClicks = 0;
+                
+                System.out.println("\n\n#################################");
+                
+                Event exampleEvent = null;
+                for (ITaskInstance instance : entry.getKey().getInstances()) {
+                    List<List<Event>> clicksOnIdenticalButton =
+                        getSubsequentClicksOnIdenticalButton((IIterationInstance) instance);
+                    
+                    if (clicksOnIdenticalButton != null) {
+                        multipleClickCount += clicksOnIdenticalButton.size();
+                        
+                        for (List<Event> subsequence : clicksOnIdenticalButton) {
+                            exampleEvent = subsequence.get(0);
+                            System.out.println(exampleEvent.getTimestamp());
+                            
+                            Event endEvent = subsequence.get(subsequence.size() - 1);
+                            long timeDiff = endEvent.getTimestamp() - exampleEvent.getTimestamp();
+                            
+                            cummulatedWaitingTime += timeDiff;
+                            numberOfAdditionalClicks += subsequence.size() - 1;
+                        }
+                    }
+                    
+                    allClickCount += ((IIterationInstance) instance).size();
+                }
+                
+                parameters.put("multipleClickCount", multipleClickCount);
+                parameters.put("allClickCount", allClickCount);
+                parameters.put("averageWaitingTime",
+                               (cummulatedWaitingTime / (numberOfAdditionalClicks * 1000)));
+                
+                parameters.put("button", exampleEvent.getTarget());
+                
+                parameters.put("task", entry.getKey());
+                
+                results.addDefect
+                    (severity, UsabilityDefectDescription.MISSING_FEEDBACK, parameters);
+            }
+        }
+    }
+
+    /**
+     * 
+     */
+    private Map<ITask, Integer> getTasksShowingMissingFeedback(Collection<ITask> tasks) {
+        Map<ITask, Integer> impatienceRatios = new HashMap<ITask, Integer>();
+        
+        for (ITask task : tasks) {
+            if (isSubsequentClickOnButton(task))  {
+                int ratio = getAverageRatioOfUserImpatience((IIteration) task);
+                
+                if (ratio > 0) {
+                    impatienceRatios.put(task, ratio);
+                }
+            }
+        }
+        
+        return impatienceRatios;
+    }
+
+    /**
+     *
+     */
+    private boolean isSubsequentClickOnButton(ITask task) {
+        if (!(task instanceof IIteration)) {
+            return false;
+        }
+        
+        if (!(((IIteration) task).getMarkedTask() instanceof IEventTask)) {
+            return false;
+        }
+        
+        IEventTask childTask = (IEventTask) ((IIteration) task).getMarkedTask();
+        
+        if ((childTask.getInstances() != null) && (childTask.getInstances().size() > 0)) {
+            Event event =
+                ((IEventTaskInstance) childTask.getInstances().iterator().next()).getEvent();
+            
+            return
+                ((event.getType() instanceof MouseClick) && (event.getTarget() instanceof IButton));
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     *
+     */
+    private int getAverageRatioOfUserImpatience(IIteration task) {
+        if (task.getInstances().size() > 0) {
+            int cummulativeImpatienceRatio = 0;
+            for (ITaskInstance instance : task.getInstances()) {
+                cummulativeImpatienceRatio += getImpatienceRatio((IIterationInstance) instance);
+            }
+
+            return cummulativeImpatienceRatio / task.getInstances().size();
+        }
+        else {
+            return 0;
+        }
+    }
+
+    /**
+     *
+     */
+    private long getImpatienceRatio(IIterationInstance instance) {
+        List<List<Event>> clicksOnIdenticalButton = getSubsequentClicksOnIdenticalButton(instance);
+        
+        if (clicksOnIdenticalButton != null) {
+            long cummulativeImpatience = 0;
+            
+            for (List<Event> subsequence : clicksOnIdenticalButton) {
+                int startIndex = 0;
+                int endIndex = 1;
+                
+                while (endIndex < subsequence.size()) {
+                    Event startEvent = subsequence.get(startIndex);
+
+                    boolean includeNext = false;
+                    
+                    if ((endIndex + 1) < subsequence.size()) {
+                        Event nextEvent = subsequence.get(endIndex + 1);
+                        long extendedTimeDiff =
+                            nextEvent.getTimestamp() - startEvent.getTimestamp();
+                        includeNext = extendedTimeDiff < 15000;
+                    }
+                    
+                    if (!includeNext && ((endIndex - startIndex) >= 1)) {
+                        Event endEvent = subsequence.get(endIndex);
+                        long timeDiff = endEvent.getTimestamp() - startEvent.getTimestamp();
+                        
+                        if ((((endIndex - startIndex) > 1) || (timeDiff > 1000)) &&
+                            (timeDiff < 15000))
+                        {
+                            // the user clicked on the same link several times. In case of only two
+                            // clicks, this was not occasionally, as the time differences between
+                            // the clicks is above one second. And it is also due to impatience, as
+                            // it is below 15 seconds (everything above 15 seconds is considered a
+                            // new action e.g. clicking again on a download link to download a
+                            // file a second time
+                            cummulativeImpatience += timeDiff * (endIndex - startIndex);
+                        }
+                        
+                        startIndex = endIndex;
+                    }
+                    endIndex++;
+                }
+            }
+            
+            return cummulativeImpatience;
+        }
+
+        return 0;
+    }
+
+
+    /**
+     *
+     */
+    private List<List<Event>> getSubsequentClicksOnIdenticalButton(IIterationInstance instance) {
+        if (instance.size() >= 2) {
+            List<List<Event>> result = new LinkedList<List<Event>>();
+            List<Event> currentList = new LinkedList<Event>();
+            for (int i = 0; i < instance.size(); i++) {
+                Event event = ((IEventTaskInstance) instance.get(i)).getEvent();
+                
+                if (currentList.size() == 0) {
+                    // initially fill the current list with first event
+                    currentList.add(event);
+                }
+                else if (currentList.get(currentList.size() - 1).getTarget() == event.getTarget()) {
+                    // check if the targets are really identical. A check for equal targets would
+                    // also reveal a re-click on a semantically equal target in a distinct view.
+                    
+                    // a further event with an identical target has been detected. Add it to the
+                    // current list, as well.
+                    currentList.add(event);
+                }
+                else {
+                    // the current target is not identical to the previous one
+                    if (currentList.size() > 1) {
+                        // there were several preceding events with identical targets. Memorize
+                        // this.
+                        result.add(currentList);
+                        currentList = new LinkedList<Event>();
+                    }
+                    else {
+                        currentList.clear();
+                    }
+                    
+                    // a new list of events with identical targets may start. Add the current
+                    // event as the first one to the list.
+                    currentList.add(event);
+                }
+            }
+
+            if (currentList.size() > 1) {
+                result.add(currentList);
+            }
+            
+            if (result.size() > 0) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java	(revision 1493)
@@ -0,0 +1,166 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class RequiredInefficientActionsRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        Map<ITask, double[]> smellingTasks = getInefficientActionStatistics(taskModel.getTasks());
+        analyzeTasksWithInefficientActions(smellingTasks, results, taskModel);
+
+        return results;
+    }
+
+    /**
+     *
+     */
+    private void analyzeTasksWithInefficientActions(Map<ITask, double[]>      smellingTasks,
+                                                    UsabilityEvaluationResult results,
+                                                    ITaskModel                taskModel)
+    {
+
+        for (Map.Entry<ITask, double[]> entry : smellingTasks.entrySet()) {
+            DescriptiveStatistics stats = new DescriptiveStatistics(entry.getValue());
+            
+            int ratio = (int) (1000 * stats.getMean());
+
+            UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                (ratio, 500, 300, 200, 100, entry.getKey(), taskModel);
+
+            if (severity != null) {
+                Map<String, Object> parameters = new HashMap<String, Object>();
+                parameters.put("task", entry.getKey());
+                parameters.put("ratio", (ratio / 10));
+
+                results.addDefect
+                    (severity, UsabilityDefectDescription.INEFFICIENT_ACTIONS, parameters);
+            }
+        }
+    }
+
+    /**
+     * 
+     */
+    private Map<ITask, double[]> getInefficientActionStatistics(Collection<ITask> tasks) {
+        Map<ITask, double[]> inefficientActionRatios = new HashMap<ITask, double[]>();
+        
+        for (ITask task : tasks) {
+            if (taskMustBeChecked(task))  {
+                double[] ratios = getRatiosOfInefficientActionsInInstances(task);
+                
+                for (int i = 0; i < ratios.length; i++) {
+                    if (ratios[i] > 0) {
+                        // there is at least on inefficient action
+                        inefficientActionRatios.put(task, ratios);
+                        break;
+                    }
+                }
+            }
+        }
+        
+        return inefficientActionRatios;
+    }
+
+    /**
+     *
+     */
+    private boolean taskMustBeChecked(ITask task) {
+        if ((task instanceof IEventTask) || (task instanceof IMarkingTemporalRelationship)) {
+            // event tasks are not considered
+            // marking temporal relationships have a child, that is more important, but it will
+            // be checked independently as all tasks of a task model are checked separately
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    /**
+     *
+     */
+    private double[] getRatiosOfInefficientActionsInInstances(ITask task) {
+        Collection<ITaskInstance> instances = task.getInstances();
+        
+        double[] ratios = new double[instances.size()];
+        int index = 0;
+        for (ITaskInstance instance : instances) {
+            ratios[index++] = getRatioOfInefficientActionsInInstance(instance);
+        }
+        
+        return ratios;
+    }
+
+    /**
+     *
+     */
+    private double getRatioOfInefficientActionsInInstance(ITaskInstance instance) {
+        final int[] count = new int[2];
+        count[0] = 0;
+        count[1] = 0;
+        
+        instance.accept(new DefaultTaskInstanceTraversingVisitor() {
+            @Override
+            public void visit(IEventTaskInstance eventTaskInstance) {
+                if (isInefficientAction(eventTaskInstance.getEvent())) {
+                    count[0]++;
+                }
+                
+                count[1]++;
+            }
+            
+        });
+        
+        return (double) count[0] / count[1];
+    }
+
+    /**
+     *
+     */
+    private boolean isInefficientAction(Event event) {
+        return (event.getType() instanceof Scroll);
+    }
+
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredScrollRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredScrollRule.java	(revision 1335)
+++ 	(revision )
@@ -1,206 +1,0 @@
-//   Copyright 2012 Georg-August-Universität Göttingen, Germany
-//
-//   Licensed under the Apache License, Version 2.0 (the "License");
-//   you may not use this file except in compliance with the License.
-//   You may obtain a copy of the License at
-//
-//       http://www.apache.org/licenses/LICENSE-2.0
-//
-//   Unless required by applicable law or agreed to in writing, software
-//   distributed under the License is distributed on an "AS IS" BASIS,
-//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//   See the License for the specific language governing permissions and
-//   limitations under the License.
-
-package de.ugoe.cs.autoquest.usability;
-
-import java.text.DecimalFormat;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import de.ugoe.cs.autoquest.eventcore.IEventType;
-import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
-
-/**
- * TODO comment
- * 
- * @version $Revision: $ $Date: 16.07.2012$
- * @author 2012, last modified by $Author: pharms$
- */
-public class RequiredScrollRule implements UsabilityEvaluationRule {
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
-     */
-    @Override
-    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
-        Map<ITask, Integer> smellingTasks = getTasksStartingWithScroll(taskModel.getTasks());
-
-        UsabilityEvaluationResult results = new UsabilityEvaluationResult();
-        analyzeTasksStartingWithScroll(smellingTasks, results);
-
-        return results;
-    }
-
-    /**
-     *
-     */
-    private void analyzeTasksStartingWithScroll(Map<ITask, Integer>       smellingTasks,
-                                                UsabilityEvaluationResult results)
-    {
-
-        for (Map.Entry<ITask, Integer> entry : smellingTasks.entrySet()) {
-            float ratio = entry.getValue() / (float) entry.getKey().getInstances().size();
-
-            UsabilityDefectSeverity severity = null;
-            if (ratio > 0.9) {
-                severity = UsabilityDefectSeverity.HIGH;
-            }
-            else if (ratio > 0.6) {
-                severity = UsabilityDefectSeverity.MEDIUM;
-            }
-            else if (ratio > 0.4) {
-                severity = UsabilityDefectSeverity.LOW;
-            }
-            else if (ratio > 0.2) {
-                severity = UsabilityDefectSeverity.INFO;
-            }
-
-            if (severity != null) {
-                Map<String, String> parameters = new HashMap<String, String>();
-                parameters.put("task", entry.getKey().toString());
-                parameters.put("scrollRatio", DecimalFormat.getInstance().format(ratio * 100));
-
-                results.addDefect(severity, UsabilityDefectDescription.SCROLL_REQUIRED, parameters);
-            }
-        }
-    }
-
-    /**
-     * 
-     */
-    private Map<ITask, Integer> getTasksStartingWithScroll(Collection<ITask> tasks) {
-        Map<ITask, Integer> scrollCounts = new HashMap<ITask, Integer>();
-        
-        for (ITask task : tasks) {
-            // only sequences are important for required scrolls
-            if (task instanceof ISequence) {
-                int count = countInstancesStartingWithScroll(task);
-                if (count > 0) {
-                    scrollCounts.put(task, count);
-                }
-            }
-        }
-        
-        return scrollCounts;
-    }
-
-    /**
-     *
-     */
-    private int countInstancesStartingWithScroll(ITask task) {
-        Collection<ITaskInstance> instances = task.getInstances();
-        
-        int counter = 0;
-        for (ITaskInstance instance : instances) {
-            if (startsWithScroll(instance)) {
-                counter++;
-            }
-        }
-        
-        return counter;
-    }
-
-    /**
-     *
-     */
-    private boolean startsWithScroll(ITaskInstance instance) {
-        if (instance instanceof ISequenceInstance) {
-            ITaskInstance firstChild = ((ISequenceInstance) instance).size() > 1 ?
-                ((ISequenceInstance) instance).get(0) : null;
-
-            if (firstChild == null) {
-                throw new IllegalArgumentException
-                    ("instance of a sequence must have at least two children");
-            }
-
-            if (startsWithScroll(firstChild)) {
-                return true;
-            }
-        }
-        else if (instance instanceof ISelectionInstance) {
-            ITaskInstance child = ((ISelectionInstance) instance).getChild();
-            
-            if (child != null) {
-                return startsWithScroll(child);
-            }
-            else {
-                throw new IllegalArgumentException("instance of a selection must have a child");
-            }
-        }
-        else if (instance instanceof IIterationInstance) {
-            ITaskInstance firstChild = ((IIterationInstance) instance).size() > 0 ?
-                ((IIterationInstance) instance).get(0) : null;
-
-            if (firstChild == null) {
-                throw new IllegalArgumentException
-                    ("instance of an iteration must have at least one child");
-            }
-
-            if (startsWithScroll(firstChild)) {
-                return true;
-            }
-        }
-        else if (instance instanceof IOptionalInstance) {
-            ITaskInstance child = ((IOptionalInstance) instance).getChild();
-            
-            if (child != null) {
-                return startsWithScroll(child);
-            }
-        }
-        else if (isScroll(instance)) {
-            return true;
-        }
-        
-        return false;
-    }
-
-    /**
-     * @param firstChild
-     * @return
-     */
-    private boolean isScroll(ITaskInstance instance) {
-        ITaskInstance instanceToCheck = instance;
-        
-        if (instanceToCheck instanceof IIterationInstance) {
-            instanceToCheck = ((IIterationInstance) instanceToCheck).size() > 0 ?
-                ((IIterationInstance) instanceToCheck).get(0) : null;
-
-            if (instanceToCheck == null) {
-                throw new IllegalArgumentException
-                    ("instance of an iteration must have at least one child");
-            }
-        }
-        
-        if (instanceToCheck instanceof IEventTaskInstance) {
-            IEventType type = ((IEventTaskInstance) instanceToCheck).getEvent().getType();
-            
-            return (type instanceof Scroll);
-        }
-        
-        return false;
-    }
-
-}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TargetDistanceRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TargetDistanceRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TargetDistanceRule.java	(revision 1493)
@@ -0,0 +1,156 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.eventcore.IEventTarget;
+import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class TargetDistanceRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        checkForTargetDistances(results, taskModel);
+
+        return results;
+    }
+
+    /**
+     * 
+     */
+    private void checkForTargetDistances(UsabilityEvaluationResult results, ITaskModel taskModel) {
+        for (ITask task : taskModel.getTasks()) {
+            if (task instanceof ISequence) {
+
+                int cummulativeNoOfHops = 0;
+                int cummulativeDistance = 0;
+
+                for (ITaskInstance instance : task.getInstances()) {
+                    int[] stats = getTargetDistance(instance);
+                    cummulativeNoOfHops += stats[0] - 1;
+                    cummulativeDistance += stats[1];
+                }
+
+                createHighTargetDisanceIfRequired
+                    (cummulativeNoOfHops, cummulativeDistance, task, results, taskModel);
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    private int[] getTargetDistance(ITaskInstance instance) {
+        List<IEventTarget> eventTargets = new LinkedList<IEventTarget>();
+        getEventTargets(instance, eventTargets);
+        int noOfGUIElements = eventTargets.size();
+        int distance = 0;
+        
+        while (eventTargets.size() > 1) {
+            distance += getDistance(eventTargets.get(0), eventTargets.get(1));
+            eventTargets.remove(0);
+        }
+        
+        return new int[] { noOfGUIElements, distance };
+    }
+
+    /**
+     *
+     */
+    private int getDistance(IEventTarget eventTarget1, IEventTarget eventTarget2) {
+        if ((eventTarget1 instanceof IGUIElement) && (eventTarget2 instanceof IGUIElement)) {
+            return (int)
+                (1000 * (((IGUIElement) eventTarget1).getDistanceTo((IGUIElement) eventTarget2)));
+        }
+        else if (eventTarget1.equals(eventTarget2)) {
+            return 0;
+        }
+        else {
+            return 1000;
+        }
+    }
+
+    /**
+     *
+     */
+    private void getEventTargets(ITaskInstance instance, final List<IEventTarget> eventTargets) {
+        instance.accept(new DefaultTaskInstanceTraversingVisitor() {
+            @Override
+            public void visit(IEventTaskInstance eventTaskInstance) {
+                if (!(eventTaskInstance.getEvent().getType() instanceof Scroll)) {
+                    eventTargets.add(eventTaskInstance.getEvent().getTarget());
+                }
+            }
+        });
+    }
+
+    /**
+     *
+     */
+    private void createHighTargetDisanceIfRequired(int                       cummulativeNoOfHops,
+                                                   int                       cummulativeDistance,
+                                                   ITask                     task,
+                                                   UsabilityEvaluationResult results,
+                                                   ITaskModel                taskModel)
+    {
+        if ((cummulativeDistance > 0) && (cummulativeNoOfHops > 0)) {
+            int ratio = cummulativeDistance / cummulativeNoOfHops;
+
+            // for HTML: 800 means not even on the same server
+            // for HTML: 600 means not on the same page
+            // for HTML: 501 means in average not on the same page
+            UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                (ratio, 800, 600, 501, 501, task, taskModel);
+
+            if (severity != null) {
+                double averageNoOfGUIElements =
+                    ((double) cummulativeNoOfHops / task.getInstances().size()) + 1;
+                
+                Map<String, Object> parameters = new HashMap<String, Object>();
+                parameters.put("task", task);
+                parameters.put("noOfGUIElements", averageNoOfGUIElements);
+                parameters.put("distance", ((double) ratio / 1000));
+
+                results.addDefect
+                    (severity, UsabilityDefectDescription.HIGH_TARGET_DISTANCE, parameters);
+            }
+        }
+    }
+
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskCooccurrenceRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskCooccurrenceRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskCooccurrenceRule.java	(revision 1493)
@@ -0,0 +1,150 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class TaskCooccurrenceRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        checkForCooccurrences(results, taskModel);
+
+        return results;
+    }
+
+    /**
+     * 
+     */
+    private void checkForCooccurrences(UsabilityEvaluationResult results, ITaskModel taskModel) {
+        for (ITask task : taskModel.getTasks()) {
+            // only sequences are important for task cooccurrences
+            if (task instanceof ISequence) {
+                ISequence sequence = (ISequence) task;
+                int index1 = 0;
+                int index2 = 1;
+                List<ITask> children = sequence.getChildren();
+                
+                while (index2 < children.size()) {
+                    ITask task1 = children.get(index1);
+                    ITask task2 = children.get(index2);
+                    ITaskInfo info1 = taskModel.getTaskInfo(task1);
+                    ITaskInfo info2 = taskModel.getTaskInfo(task2);
+                    
+                    int ratioTask1 = 1000 * info1.getMeasureValue(TaskMetric.COUNT, sequence) /
+                        info1.getMeasureValue(TaskMetric.COUNT);
+                    int ratioTask2 = 1000 * info2.getMeasureValue(TaskMetric.COUNT, sequence) /
+                            info2.getMeasureValue(TaskMetric.COUNT);
+                    
+                    createSucceededDefectIfRequired(ratioTask1, task1, task2, results, taskModel);
+                    createPrecededDefectIfRequired(ratioTask2, task1, task2, results, taskModel);
+                    
+                    index1 = index2;
+                    index2++;
+                }
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    private void createSucceededDefectIfRequired(int                       ratio,
+                                                 ITask                     task1,
+                                                 ITask                     task2,
+                                                 UsabilityEvaluationResult results,
+                                                 ITaskModel                taskModel)
+    {
+        //TODO document magic numbers
+        UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+            (ratio, 900, 700, 500, 300, task1, taskModel);
+
+        if (!isScroll(task1) && !isScroll(task2) && (severity != null)) {
+            Map<String, Object> parameters = new HashMap<String, Object>();
+            parameters.put("task1", task1);
+            parameters.put("task2", task2);
+            parameters.put("ratio", (ratio / 10));
+
+            results.addDefect(severity, UsabilityDefectDescription.COOCCURENCE_SUCCEED, parameters);
+        }
+    }
+
+    /**
+     *
+     */
+    private void createPrecededDefectIfRequired(int                       ratio,
+                                                ITask                     task1,
+                                                ITask                     task2,
+                                                UsabilityEvaluationResult results,
+                                                ITaskModel                taskModel)
+    {
+        //TODO document magic numbers
+        UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+            (ratio, 900, 700, 500, 300, task2, taskModel);
+
+        if (!isScroll(task1) && !isScroll(task2) && (severity != null)) {
+            Map<String, Object> parameters = new HashMap<String, Object>();
+            parameters.put("task1", task1);
+            parameters.put("task2", task2);
+            parameters.put("ratio", (ratio / 10));
+
+            results.addDefect(severity, UsabilityDefectDescription.COOCCURENCE_PRECED, parameters);
+        }
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param task1
+     * @return
+     */
+    private boolean isScroll(ITask task) {
+        if (task instanceof IEventTask) {
+            return ((IEventTaskInstance) ((IEventTask) task).getInstances().iterator().next()).getEvent().getType() instanceof Scroll;
+        }
+        else if (task instanceof IIteration) {
+            return isScroll(((IIteration) task).getMarkedTask());
+        }
+        
+        return false;
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskTreeTestRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskTreeTestRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskTreeTestRule.java	(revision 1493)
@@ -0,0 +1,80 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceVisitor;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class TaskTreeTestRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        checkTimestamps(taskModel);
+
+        return results;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param taskModel
+     */
+    private void checkTimestamps(ITaskModel taskModel) {
+        for (IUserSession session : taskModel.getUserSessions()) {
+            ITaskInstanceVisitor visitor = new DefaultTaskInstanceTraversingVisitor() {
+                Event lastEvent = null;
+                
+                @Override
+                public void visit(IEventTaskInstance eventTaskInstance) {
+                    if (lastEvent != null) {
+                        if (eventTaskInstance.getEvent().getTimestamp() < lastEvent.getTimestamp()) {
+                            System.out.println("timestamp problem encountered:");
+                            System.out.println("  " + lastEvent.getTimestamp() + "  " + lastEvent);
+                            System.out.println("  " + eventTaskInstance.getEvent().getTimestamp() + "  " + eventTaskInstance.getEvent());
+                        }
+                    }
+                    
+                    lastEvent = eventTaskInstance.getEvent();
+                }
+                
+            };
+            
+            for (ITaskInstance instance : session) {
+                visitor.visit(instance);
+            }
+        }
+        
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TextInputStatisticsRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TextInputStatisticsRule.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TextInputStatisticsRule.java	(revision 1493)
@@ -15,5 +15,4 @@
 package de.ugoe.cs.autoquest.usability;
 
-import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -57,5 +56,5 @@
         calculateStatistics(taskModel.getUserSessions(), statistics);
 
-        UsabilityEvaluationResult results = new UsabilityEvaluationResult();
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
         analyzeStatistics(statistics, results);
 
@@ -80,26 +79,16 @@
                                      UsabilityEvaluationResult results)
     {
-        float allTextFieldInputs =
+        int allTextFieldInputs =
             statistics.getNoOfTextFieldInputs() + statistics.getNoOfTextAreaInputs();
 
-        float ratio = allTextFieldInputs / (float) statistics.getNoOfAllEvents();
-
-        UsabilityDefectSeverity severity = null;
-        if (ratio > 0.9) {
-            severity = UsabilityDefectSeverity.HIGH;
-        }
-        else if (ratio > 0.7) {
-            severity = UsabilityDefectSeverity.MEDIUM;
-        }
-        else if (ratio > 0.5) {
-            severity = UsabilityDefectSeverity.LOW;
-        }
-        else if (ratio > 0.3) {
-            severity = UsabilityDefectSeverity.INFO;
-        }
-
+        int ratio = 1000 * allTextFieldInputs / statistics.getNoOfAllEvents();
+
+        // TODO comment magic numbers
+        UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+            (ratio, 900, 700, 500, 300);
+        
         if (severity != null) {
-            Map<String, String> parameters = new HashMap<String, String>();
-            parameters.put("textInputRatio", DecimalFormat.getInstance().format(ratio * 100));
+            Map<String, Object> parameters = new HashMap<String, Object>();
+            parameters.put("textInputRatio", (ratio / 10));
 
             results.addDefect
@@ -122,47 +111,36 @@
             int noOfUsagesOfTextField1WithSameTextInTextField2 = entry.enteredTexts.size();
             
-            float ratioTextField1 =
-                noOfUsagesOfTextField1WithSameTextInTextField2 / (float) noOfUsagesOfTextField1;
-            
-            float ratioTextField2 =
-                noOfUsagesOfTextField1WithSameTextInTextField2 / (float) noOfUsagesOfTextField2;
-            
-            createTextFieldEntryRepetitionDefect
-                (ratioTextField1, entry.textField1, entry.textField2, results);
-            
-            createTextFieldEntryRepetitionDefect
-                (ratioTextField2, entry.textField2, entry.textField1, results);
-            
-        }
-    }
-
-    /**
-     *
-     */
-    private void createTextFieldEntryRepetitionDefect(float                     ratioOfEqualEntries,
+            int ratioTextField1 = 
+                1000 * noOfUsagesOfTextField1WithSameTextInTextField2 / noOfUsagesOfTextField1;
+            
+            int ratioTextField2 =
+                1000 * noOfUsagesOfTextField1WithSameTextInTextField2 / noOfUsagesOfTextField2;
+
+            createTextFieldEntryRepetitionDefect(ratioTextField1, entry.textField1,
+                                                 entry.textField2, results);
+            
+            createTextFieldEntryRepetitionDefect(ratioTextField2, entry.textField2,
+                                                 entry.textField1, results);
+            
+        }
+    }
+
+    /**
+     *
+     */
+    private void createTextFieldEntryRepetitionDefect(int                       ratioOfEqualEntries,
                                                       ITextField                textField1,
                                                       ITextField                textField2,
                                                       UsabilityEvaluationResult results)
     {
-        UsabilityDefectSeverity severity = null;
-        if (ratioOfEqualEntries > 0.9) {
-            severity = UsabilityDefectSeverity.HIGH;
-        }
-        else if (ratioOfEqualEntries > 0.5) {
-            severity = UsabilityDefectSeverity.MEDIUM;
-        }
-        else if (ratioOfEqualEntries > 0.2) {
-            severity = UsabilityDefectSeverity.LOW;
-        }
-        else if (ratioOfEqualEntries > 0.1) {
-            severity = UsabilityDefectSeverity.INFO;
-        }
+        // TODO comment magic numbers
+        UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+            (ratioOfEqualEntries, 900, 500, 200, 100);
         
         if (severity != null) {
-            Map<String, String> parameters = new HashMap<String, String>();
-            parameters.put("textRepetitionRatio",
-                           DecimalFormat.getInstance().format(ratioOfEqualEntries * 100));
-            parameters.put("textField1", textField1.toString());
-            parameters.put("textField2", textField2.toString());
+            Map<String, Object> parameters = new HashMap<String, Object>();
+            parameters.put("textRepetitionRatio", (ratioOfEqualEntries / 10));
+            parameters.put("textField1", textField1);
+            parameters.put("textField2", textField2);
 
             results.addDefect
@@ -192,28 +170,22 @@
             }
 
-            float ratio = (float) noLetterOrDigitCount / (float) allCharactersCount;
-
-            UsabilityDefectSeverity severity = null;
-            if (ratio > 0.1) { // every 10th sign
-                severity = UsabilityDefectSeverity.HIGH;
-            }
-            else if (ratio > 0.05) { // every 20th sign
-                severity = UsabilityDefectSeverity.MEDIUM;
-            }
-            else if (ratio > 0.02) { // every 50th sign
-                severity = UsabilityDefectSeverity.LOW;
-            }
-            else if (ratio > 0.01) { // every 100th sign
-                severity = UsabilityDefectSeverity.INFO;
-            }
+            int ratio = 1000 * noLetterOrDigitCount / allCharactersCount;
+
+            UsabilityDefectSeverity severity =
+                UsabilityDefectSeverity.getSeverity(ratio,
+                                                    100, // every 10th sign
+                                                    50, // every 20th sign
+                                                    20, // every 50th sign
+                                                    10 // every 100th sign
+                                                    );
 
             if (severity != null) {
-                Map<String, String> parameters = new HashMap<String, String>();
-                parameters.put("textField", textField.toString());
-                parameters.put("noLetterOrDigitRatio",
-                               DecimalFormat.getInstance().format(ratio * 100));
+                Map<String, Object> parameters = new HashMap<String, Object>();
+                parameters.put("textField", textField);
+                parameters.put("noLetterOrDigitRatio", (ratio / 10));
 
                 results.addDefect
-                    (severity, UsabilityDefectDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO, parameters);
+                    (severity, UsabilityDefectDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO,
+                     parameters);
             }
         }
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java	(revision 1493)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java	(revision 1493)
@@ -0,0 +1,267 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.usability;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
+import de.ugoe.cs.autoquest.eventcore.guimodel.ICheckBox;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IComboBox;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IListBox;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IMenuButton;
+import de.ugoe.cs.autoquest.eventcore.guimodel.ITextArea;
+import de.ugoe.cs.autoquest.eventcore.guimodel.ITextField;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+
+/**
+ * TODO comment
+ * 
+ * @version $Revision: $ $Date: 16.07.2012$
+ * @author 2012, last modified by $Author: pharms$
+ */
+public class UnusedGUIElementsRule implements UsabilityEvaluationRule {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
+     */
+    @Override
+    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
+
+        GUIModel guiModel = getGUIModel(taskModel);
+        Set<IGUIElement> allGUIElements = getAllGUIElements(guiModel);
+        Set<IGUIElement> usedGUIElements = getUsedGUIElements(taskModel);
+        List<IGUIElement> unusedGUIElements = getUnusedGUIElements(usedGUIElements, allGUIElements);
+        handleUnusedGUIElements(unusedGUIElements, allGUIElements, results);
+
+        return results;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param unusedGUIElements
+     * @param results
+     */
+    private void handleUnusedGUIElements(List<IGUIElement>         unusedGUIElements,
+                                         Set<IGUIElement>          allGUIElements,
+                                         UsabilityEvaluationResult results)
+    {
+        int ratio = 1000 * unusedGUIElements.size() / allGUIElements.size();
+        
+        UsabilityDefectSeverity severity =
+            UsabilityDefectSeverity.getSeverity(ratio, 200, 100, 50, 25);
+
+        if (severity != null) {
+            Map<String, Object> parameters = new HashMap<String, Object>();
+
+            parameters.put("ratio", ratio / 10);
+            parameters.put("noOfUnused", unusedGUIElements.size());
+            parameters.put("noOfAll", allGUIElements.size());
+            parameters.put("unusedGuiElements", unusedGUIElements);
+            
+            results.addDefect
+                (severity, UsabilityDefectDescription.UNUSED_GUI_ELEMENTS, parameters);
+        }
+     }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param taskModel
+     * @return
+     */
+    private GUIModel getGUIModel(ITaskModel taskModel) {
+        for (ITask task : taskModel.getTasks()) {
+            if (task instanceof IEventTask) {
+                for (ITaskInstance instance : task.getInstances()) {
+                    Event event = ((IEventTaskInstance) instance).getEvent();
+                    
+                    if (event.getTarget() instanceof IGUIElement) {
+                        return ((IGUIElement) event.getTarget()).getGUIModel();
+                    }
+                }
+            }
+        }
+        
+        return null;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param taskModel
+     */
+    private Set<IGUIElement> getUsedGUIElements(ITaskModel taskModel) {
+        Set<IGUIElement> usedGUIElements = new HashSet<IGUIElement>();
+        
+        for (ITask task : taskModel.getTasks()) {
+            if (task instanceof IEventTask) {
+                for (ITaskInstance instance : task.getInstances()) {
+                    Event event = ((IEventTaskInstance) instance).getEvent();
+                    
+                    if (event.getTarget() instanceof IGUIElement) {
+                        usedGUIElements.add((IGUIElement) event.getTarget());
+                    }
+                }
+            }
+        }
+        
+        return usedGUIElements;
+    }
+    
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param taskModel
+     */
+    private Set<IGUIElement> getAllGUIElements(GUIModel guiModel) {
+        Set<IGUIElement> allGUIElements = new HashSet<IGUIElement>();
+        
+        if (guiModel != null) {
+            GUIModel.Traverser traverser = guiModel.getTraverser();
+
+            IGUIElement currentGUIElement = null;
+            do {
+                if (traverser.hasFirstChild()) {
+                    currentGUIElement = traverser.firstChild();
+                }
+                else if (traverser.hasNextSibling()) {
+                    currentGUIElement = traverser.nextSibling();
+                }
+                else {
+                    while (currentGUIElement != null) {
+                        currentGUIElement = traverser.parent();
+                        if (traverser.hasNextSibling()) {
+                            currentGUIElement = traverser.nextSibling();
+                            break;
+                        }
+                    }
+                }
+
+                if (isRelevant(currentGUIElement)) {
+                    allGUIElements.add(currentGUIElement);
+                }
+            }
+            while (currentGUIElement != null);
+        }
+        
+        return allGUIElements;
+    }
+    
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param taskModel
+     */
+    private List<IGUIElement> getUnusedGUIElements(Set<IGUIElement> usedGUIElements,
+                                                   Set<IGUIElement> allGUIElements)
+    {
+        List<IGUIElement> unusedGUIElements = new LinkedList<IGUIElement>();
+        for (IGUIElement currentGUIElement : allGUIElements) {
+            if (isRelevant(currentGUIElement) &&
+                !belongsToUsedGUIElements(currentGUIElement, usedGUIElements))
+            {
+                unusedGUIElements.add(currentGUIElement);
+            }
+        }
+        
+        return unusedGUIElements;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param currentGUIElement
+     * @param usedGUIElements
+     * @return
+     */
+    private boolean belongsToUsedGUIElements(IGUIElement      relevantGUIElement,
+                                             Set<IGUIElement> usedGUIElements)
+    {
+        if (usedGUIElements.contains(relevantGUIElement)) {
+            return true;
+        }
+        else {
+            // in some cases, the events are recorded for the children of the relevant GUI elements
+            // therefore, check the children, as well.
+            List<IGUIElement> children =
+                relevantGUIElement.getGUIModel().getChildren(relevantGUIElement);
+            
+            if (children != null) {
+                for (IGUIElement child : children) {
+                    if (belongsToUsedGUIElements(child, usedGUIElements)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param currentGUIElement
+     * @return
+     */
+    private boolean isRelevant(IGUIElement currentGUIElement) {
+        if (currentGUIElement == null) {
+            return false;
+        }
+        
+        if ((currentGUIElement instanceof IButton) ||
+            (currentGUIElement instanceof ICheckBox) ||
+            (currentGUIElement instanceof IComboBox) ||
+            (currentGUIElement instanceof IListBox) ||
+            (currentGUIElement instanceof IMenuButton) ||
+            (currentGUIElement instanceof ITextArea) ||
+            (currentGUIElement instanceof ITextField))
+        {
+            return true;
+        }
+        
+        return false;
+    }
+}
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefect.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefect.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefect.java	(revision 1493)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.usability;
 
+import java.util.List;
 import java.util.Map;
 
@@ -32,11 +33,10 @@
 
     /** */
-    private Map<String, String> descriptionParameters;
+    private Map<String, Object> descriptionParameters;
 
     /**
      *
      */
-    UsabilityDefect(UsabilityDefectSeverity severity, UsabilityDefectDescription description)
-    {
+    UsabilityDefect(UsabilityDefectSeverity severity, UsabilityDefectDescription description) {
         this(severity, description, null);
     }
@@ -47,5 +47,5 @@
     UsabilityDefect(UsabilityDefectSeverity    severity,
                     UsabilityDefectDescription description,
-                    Map<String, String>        parameters)
+                    Map<String, Object>        parameters)
     {
         this.severity = severity;
@@ -80,4 +80,17 @@
     public String getParameterizedDescription() {
         return description.toString(descriptionParameters);
+    }
+
+    /**
+     * 
+     */
+    public List<Object> getDescriptionFragments() {
+        return description.toFragmentList(descriptionParameters);
+    }
+
+    /*
+     */
+    public String getBriefDescription() {
+        return description.getBriefDescription();
     }
 
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectDescription.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectDescription.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectDescription.java	(revision 1493)
@@ -18,4 +18,5 @@
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -33,8 +34,14 @@
 public enum UsabilityDefectDescription {
     
-    SCROLL_REQUIRED,
+    INEFFICIENT_ACTIONS,
     TEXT_FIELD_INPUT_RATIO,
     TEXT_FIELD_INPUT_REPETITIONS,
-    TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO;
+    TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO,
+    COOCCURENCE_SUCCEED,
+    COOCCURENCE_PRECED,
+    HIGH_EVENT_COVERAGE,
+    HIGH_TARGET_DISTANCE,
+    MISSING_FEEDBACK,
+    UNUSED_GUI_ELEMENTS;
 
     /** */
@@ -122,5 +129,5 @@
      * 
      */
-    public String toString(Map<String, String> parameters) throws IllegalArgumentException {
+    public String toString(Map<String, Object> parameters) throws IllegalArgumentException {
         StringBuffer result = new StringBuffer();
 
@@ -131,5 +138,5 @@
 
             if (fragment instanceof ParameterFragment) {
-                String value = null;
+                Object value = null;
                 if (parameters != null) {
                     value = parameters.get(((ParameterFragment) fragment).getParameterName());
@@ -137,5 +144,16 @@
 
                 if (value != null) {
-                    result.append(value);
+                    if (value instanceof Collection<?>) {
+                        int counter = 1;
+                        for (Object elem : ((Collection<?>) value)) {
+                            result.append('\n');
+                            result.append(counter++);
+                            result.append(".: ");
+                            result.append(elem);
+                        }
+                    }
+                    else {
+                        result.append(value.toString());
+                    }
                 }
                 else {
@@ -154,4 +172,44 @@
     }
 
+    /**
+     * 
+     */
+    public List<Object> toFragmentList(Map<String, Object> parameters)
+        throws IllegalArgumentException
+    {
+        List<Object> result = new ArrayList<Object>();
+
+        for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {
+            if (fragment instanceof ParameterFragment) {
+                Object value = null;
+                if (parameters != null) {
+                    value = parameters.get(((ParameterFragment) fragment).getParameterName());
+                }
+
+                if (value != null) {
+                    result.add(value);
+                }
+                else {
+                    throw new IllegalArgumentException
+                        ("required parameter \"" +
+                         ((ParameterFragment) fragment).getParameterName() +
+                         "\" for usability defect description " + this.name() + " not provided");
+                }
+            }
+            else {
+                result.add(getFragmentString(fragment));
+            }
+        }
+
+        return result;
+    }
+    
+    /**
+     * 
+     */
+    public String getBriefDescription() {
+        return defectDescription.briefText;
+    }
+
     /*
      * (non-Javadoc)
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectSeverity.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectSeverity.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectSeverity.java	(revision 1493)
@@ -15,4 +15,9 @@
 package de.ugoe.cs.autoquest.usability;
 
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
+
 /**
  * TODO comment
@@ -24,4 +29,99 @@
     
     INFO, LOW, MEDIUM, HIGH;
+    
+    /** */
+    static int defaultCoverageQuantile = 950;
 
+    /**
+     * 
+     */
+    static UsabilityDefectSeverity getSeverity(int ratio,
+                                               int highRatioLevel,
+                                               int mediumRatioLevel,
+                                               int lowRatioLevel,
+                                               int infoRatioLevel)
+    {
+        return getSeverity(ratio, highRatioLevel, mediumRatioLevel, lowRatioLevel, infoRatioLevel,
+                           defaultCoverageQuantile);
+    }
+
+    /**
+     * 
+     */
+    static UsabilityDefectSeverity getSeverity(int        ratio,
+                                               int        highRatioLevel,
+                                               int        mediumRatioLevel,
+                                               int        lowRatioLevel,
+                                               int        infoRatioLevel,
+                                               ITask      taskWithDefect,
+                                               ITaskModel wholeTaskModel)
+    {
+        ITaskInfo taskInfo = wholeTaskModel.getTaskInfo(taskWithDefect);
+        int eventCoverageQuantile = taskInfo.getMeasureValue(TaskMetric.EVENT_COVERAGE_QUANTILE);
+        return getSeverity(ratio, highRatioLevel, mediumRatioLevel, lowRatioLevel, infoRatioLevel,
+                           eventCoverageQuantile);
+    }
+
+    /**
+     * 
+     */
+    static UsabilityDefectSeverity getSeverity(int ratio,
+                                               int highRatioLevel,
+                                               int mediumRatioLevel,
+                                               int lowRatioLevel,
+                                               int infoRatioLevel,
+                                               int coverageQuantile)
+    {
+        int effectiveRatio = ratio;
+        
+        // event coverage ratio is in per mille. The more executed events a task covers, the more
+        // important a related usability defect.
+        /*if (eventCoverageRatio < 1) {
+            // one per mille, so one of thousand events is covered
+            effectiveRatio *= 0.2;
+        }
+        else if (eventCoverageRatio < 5) {
+            // 5 per mille, so one of 250 events is covered
+            effectiveRatio *= 0.4;
+        }
+        else if (eventCoverageRatio < 10) {
+            // 1 percent, so one of 100 events is covered
+            effectiveRatio *= 0.5;
+        }
+        else if (eventCoverageRatio < 20) {
+            // 2 percent, so one of 50 events is covered
+            effectiveRatio *= 0.6;
+        }
+        else if (eventCoverageRatio < 30) {
+            // 3 percent, so one of 33 events is covered
+            effectiveRatio *= 0.7;
+        }
+        else if (eventCoverageRatio < 40) {
+            // 4 percent, so one of 28 events is covered
+            effectiveRatio *= 0.8;
+        }
+        else if (eventCoverageRatio < 50) {
+            // 5 percent, so one of 25 events is covered
+            effectiveRatio *= 0.9;
+        }*/
+        //else {
+            // more than 5 percent, so 1 of 20 events, do not change ratio
+        //}
+        if (coverageQuantile >= defaultCoverageQuantile) {
+            if (effectiveRatio >= highRatioLevel) {
+                return UsabilityDefectSeverity.HIGH;
+            }
+            else if (effectiveRatio >= mediumRatioLevel) {
+                return UsabilityDefectSeverity.MEDIUM;
+            }
+            else if (effectiveRatio >= lowRatioLevel) {
+                return UsabilityDefectSeverity.LOW;
+            }
+            else if (effectiveRatio >= infoRatioLevel) {
+                return UsabilityDefectSeverity.INFO;
+            }
+        }
+        
+        return null;
+    }
 }
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationManager.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationManager.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationManager.java	(revision 1493)
@@ -19,4 +19,7 @@
 import java.util.logging.Level;
 
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
 import de.ugoe.cs.util.console.Console;
@@ -45,6 +48,12 @@
      */
     private void init() {
-        rules.add(new TextInputStatisticsRule());
-        rules.add(new RequiredScrollRule());
+        //rules.add(new TextInputStatisticsRule());
+        rules.add(new MissingFeedbackRule());
+        rules.add(new EventCoverageRatioRule());
+        rules.add(new RequiredInefficientActionsRule());
+        //rules.add(new TaskCooccurrenceRule());
+        rules.add(new TargetDistanceRule());
+        //rules.add(new UnusedGUIElementsRule());
+        //rules.add(new TaskTreeTestRule());
     }
 
@@ -64,17 +73,68 @@
                             " usability defects, of which " + result.getSevereDefects().size() +
                             " are severe.");
+            
+            if ((rule instanceof EventCoverageRatioRule) ||
+                (rule instanceof RequiredInefficientActionsRule) ||
+                (rule instanceof TargetDistanceRule))
+            {
+                ITask[] referredTasks = new ITask[result.getAllDefects().size()];
+
+                for (int i = 0; i < result.getAllDefects().size(); i++) {
+                    referredTasks[i] =
+                        (ITask) result.getAllDefects().get(i).getDescriptionFragments().get(1);
+                }
+                
+                int counter = 0;
+                for (int i = 0; i < referredTasks.length; i++) {
+                    for (int j = 0; j < referredTasks.length; j++) {
+                        if (isChildOf(referredTasks[i], referredTasks[j])) {
+                            counter++;
+                            break;
+                        }
+                    }
+                }
+                
+                if (counter > 0) {
+                    Console.traceln(Level.INFO, counter + " of the findings are duplicates in " +
+                                    "that they refer to tasks whose parent tasks are also " +
+                                    "referred by the findings");
+                }
+            }
         }
 
-        UsabilityEvaluationResult result = new UsabilityEvaluationResult(interimResults);
+        UsabilityEvaluationResult result = new UsabilityEvaluationResult(taskModel, interimResults);
         Console.println("the evaluation result contains " + result.getAllDefects().size() +
                         " defects, of which " + result.getSevereDefects().size() + " are severe.");
-
-        List<UsabilityDefect> defects = result.getAllDefects();
-        for (int i = 0; i < defects.size(); i++) {
-            Console.println((i + 1) + ": " + defects.get(i).getParameterizedDescription());
-        }
 
         return result;
     }
 
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param iTask
+     * @param iTask2
+     * @return
+     */
+    private boolean isChildOf(final ITask potChild, ITask potParent) {
+        
+        if (potParent instanceof IStructuringTemporalRelationship) {
+            for (ITask child : ((IStructuringTemporalRelationship) potParent).getChildren()) {
+                if ((child == potChild) || isChildOf(potChild, child)) {
+                    return true;
+                }
+            }
+        }
+        else if (potParent instanceof IMarkingTemporalRelationship) {
+            ITask child = ((IMarkingTemporalRelationship) potParent).getMarkedTask();
+            if ((child == potChild) || isChildOf(potChild, child)) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
 }
Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationResult.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationResult.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationResult.java	(revision 1493)
@@ -19,4 +19,6 @@
 import java.util.Map;
 
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
+
 /**
  * TODO comment
@@ -28,4 +30,7 @@
     
     /** */
+    private ITaskModel taskModel;
+    
+    /** */
     private List<UsabilityDefect> defects = new ArrayList<UsabilityDefect>();
 
@@ -33,6 +38,6 @@
      *
      */
-    public UsabilityEvaluationResult() {
-        // default constructor
+    public UsabilityEvaluationResult(ITaskModel taskModel) {
+        this.taskModel = taskModel;
     }
 
@@ -40,5 +45,8 @@
      *
      */
-    public UsabilityEvaluationResult(List<UsabilityEvaluationResult> results) {
+    public UsabilityEvaluationResult(ITaskModel                      taskModel,
+                                     List<UsabilityEvaluationResult> results)
+    {
+        this.taskModel = taskModel;
         for (UsabilityEvaluationResult result : results) {
             for (UsabilityDefect defect : result.getAllDefects()) {
@@ -53,5 +61,5 @@
     public void addDefect(UsabilityDefectSeverity    severity,
                           UsabilityDefectDescription description,
-                          Map<String, String>        parameters)
+                          Map<String, Object>        parameters)
     {
         defects.add(new UsabilityDefect(severity, description, parameters));
@@ -80,3 +88,10 @@
     }
 
+    /**
+     * @return the taskModel
+     */
+    public ITaskModel getTaskModel() {
+        return taskModel;
+    }
+
 }
Index: trunk/autoquest-core-usability/src/main/resources/defectDescriptions.xsd
===================================================================
--- trunk/autoquest-core-usability/src/main/resources/defectDescriptions.xsd	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/resources/defectDescriptions.xsd	(revision 1493)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xsd:schema
-  targetNamespace="http://quest"
-  xmlns:tns="http://quest"
+  targetNamespace="http://autoquest.informatik.uni-goettingen.de"
+  xmlns:tns="http://autoquest.informatik.uni-goettingen.de"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
@@ -22,4 +22,5 @@
     </xsd:choice>
     <xsd:attribute name="defectId" type="xsd:string" use="required" />
+    <xsd:attribute name="briefText" type="xsd:string" use="required" />
   </xsd:complexType>
 
Index: trunk/autoquest-core-usability/src/main/resources/defectDescriptions_en.xml
===================================================================
--- trunk/autoquest-core-usability/src/main/resources/defectDescriptions_en.xml	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/resources/defectDescriptions_en.xml	(revision 1493)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <defectDescriptions
-  xmlns="http://quest"
+  xmlns="http://autoquest.informatik.uni-goettingen.de"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://quest defectDescriptions.xsd">
+  xsi:schemaLocation="http://autoquest.informatik.uni-goettingen.de defectDescriptions.xsd">
   
-  <defectDescription defectId="TEXT_FIELD_INPUT_RATIO">
+  <defectDescription defectId="TEXT_FIELD_INPUT_RATIO" briefText="many text inputs">
     <textFragment>
       The ratio of interactions that enter text into text fields is relatively high in comparison
@@ -17,5 +17,5 @@
   </defectDescription>
   
-  <defectDescription defectId="TEXT_FIELD_INPUT_REPETITIONS">
+  <defectDescription defectId="TEXT_FIELD_INPUT_REPETITIONS" briefText="many text repetitions">
     <textFragment>
       In
@@ -36,5 +36,5 @@
   </defectDescription>
   
-  <defectDescription defectId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO">
+  <defectDescription defectId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO" briefText="many special signs">
     <parameterFragment parameterName="noLetterOrDigitRatio" />
     <textFragment>
@@ -50,18 +50,143 @@
   </defectDescription>
   
-  <defectDescription defectId="SCROLL_REQUIRED">
+  <defectDescription defectId="HIGH_EVENT_COVERAGE" briefText="often executed">
+    <textFragment>
+      The task
+    </textFragment>
+    <parameterFragment parameterName="task" />
+    <textFragment>
+      covers
+    </textFragment>
+    <parameterFragment parameterName="ratio" />
+    <textFragment>
+      % of all recorded user actions. Therefore, it should be executed with a high efficiency.
+      You should consider making the task more efficient, by minimizing the number of actions to
+      be executed by users for fulfilling this task.
+    </textFragment>
+  </defectDescription>
+  
+  <defectDescription defectId="INEFFICIENT_ACTIONS" briefText="inefficient actions">
+    <textFragment>
+      For executing task
+    </textFragment>
+    <parameterFragment parameterName="task" />
+    <textFragment>
+      , the user has to execute a high number of inefficient actions (
+    </textFragment>
+    <parameterFragment parameterName="ratio" />
+    <textFragment>
+      % in average). Such actions are, e.g., scrolls. The number of inefficient actions should
+      be as minimal as possible to increase the users efficiency in executing a task. Please
+      check the task structure for occurrences of the following event tasks and consider to prevent
+      them: scrolling.
+    </textFragment>
+  </defectDescription>
+  
+  <defectDescription defectId="COOCCURENCE_SUCCEED" briefText="usual cooccurrence">
     <textFragment>
       In
     </textFragment>
-    <parameterFragment parameterName="scrollRatio" />
+    <parameterFragment parameterName="ratio" />
     <textFragment>
       % of all occurrences, the task
     </textFragment>
+    <parameterFragment parameterName="task1" />
+    <textFragment>
+      is succeeded by
+    </textFragment>
+    <parameterFragment parameterName="task2" />
+    <textFragment>
+      . This shows, that both tasks are likely used in combination. Please consider to support the
+      execution of both tasks in one user action, e.g., by providing an appropriate button, to
+      reduce the number of actions to be performed by the user.
+    </textFragment>
+  </defectDescription>
+  
+  <defectDescription defectId="COOCCURENCE_PRECED" briefText="usual cooccurrence">
+    <textFragment>
+      In
+    </textFragment>
+    <parameterFragment parameterName="ratio" />
+    <textFragment>
+      % of all occurrences, the task
+    </textFragment>
+    <parameterFragment parameterName="task2" />
+    <textFragment>
+      is preceded by
+    </textFragment>
+    <parameterFragment parameterName="task1" />
+    <textFragment>
+      . This shows, that both tasks are likely used in combination. Please consider to support the
+      execution of both tasks in one user action, e.g., by providing an appropriate button, to
+      reduce the number of actions to be performed by the user.
+    </textFragment>
+  </defectDescription>
+  
+  <defectDescription defectId="HIGH_TARGET_DISTANCE" briefText="long way to go">
+    <textFragment>
+      For executing the task
+    </textFragment>
     <parameterFragment parameterName="task" />
     <textFragment>
-      is started with a scroll. This should be prevented as scrolling decreases the efficiency of
-      the user and indicates, that not all required information is visible at once in the
-      respective view. However, scrolling for reading of texts is no problem.
+      , the user utilizes
+    </textFragment>
+    <parameterFragment parameterName="noOfGUIElements" />
+    <textFragment>
+      GUI elements on average. As these GUI elements have a high distance to each other (
+    </textFragment>
+    <parameterFragment parameterName="distance" />
+    <textFragment>
+      on average ), they should be more colocated to ease the execution of the task for the user.
     </textFragment>
   </defectDescription>
+  
+  <defectDescription defectId="MISSING_FEEDBACK" briefText="missing feedback">
+    <textFragment>
+      A click on the button
+    </textFragment>
+    <parameterFragment parameterName="button" />
+    <textFragment>
+      seems to be missing user feedback. In
+    </textFragment>
+    <parameterFragment parameterName="multipleClickCount" />
+    <textFragment>
+      of
+    </textFragment>
+    <parameterFragment parameterName="allClickCount" />
+    <textFragment>
+      uses, the button was clicked several times. The average waiting time between two subsequent
+      clicks is
+    </textFragment>
+    <parameterFragment parameterName="averageWaitingTime" />
+    <textFragment>
+      seconds. This is typical user behavior if the user does not see progress following his
+      actions. Please consider showing the user some progress after he performed the
+      first click. This is especially important if the operation triggered with the click usually
+      takes longer than one second. This defect was observed based on task
+    </textFragment>
+    <parameterFragment parameterName="task" />
+    <textFragment>
+      .
+    </textFragment>
+  </defectDescription>
+  
+  <defectDescription defectId="UNUSED_GUI_ELEMENTS" briefText="unused GUI elements">
+    <parameterFragment parameterName="ratio" />
+    <textFragment>
+      % of the GUI elements (
+    </textFragment>
+    <parameterFragment parameterName="noOfUnused" />
+    <textFragment>
+      of
+    </textFragment>
+    <parameterFragment parameterName="noOfAll" />
+    <textFragment>
+      ) are not used. This can have several reasons. Either they are not
+      visible to the user or they are not required. If they are important, they may not be
+      recognized by the user. This can be caused by visual design or because they are too hidden.
+      If they are less important, they can either be removed from the GUI or relocated to a less
+      prominent position. The unused GUI elements are:
+    </textFragment>
+    <parameterFragment parameterName="unusedGuiElements" />
+  </defectDescription>
 </defectDescriptions>
