[orca] Rewrite accessible event handlers for Gecko content



commit e8ede32db8c57a35e393248bdded0e74b62b8f65
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Fri May 15 12:24:37 2015 -0400

    Rewrite accessible event handlers for Gecko content
    
    Fixes:
    * Not presenting the last line in a text area
    * Not repositioning location at newly-loaded fragment
    * Not presenting expanded state change in ARIA content
    * Not presenting correct radio button state in ARIA content
    * Several issues related to pyatspi cache not being updated
    * Double-presenting find results
    * Re-generating braille when not needed
    
    Also created locally-runable copies of tests which no longer exist
    at the original site and updated other tests to reflect changes in
    Firefox and Dojo.

 src/orca/formatting.py                             |    3 +
 src/orca/scripts/apps/Thunderbird/Makefile.am      |    1 -
 src/orca/scripts/apps/Thunderbird/formatting.py    |   56 --
 src/orca/scripts/apps/Thunderbird/script.py        |    5 -
 .../scripts/apps/Thunderbird/script_utilities.py   |   22 -
 .../scripts/apps/Thunderbird/speech_generator.py   |   25 -
 src/orca/scripts/default.py                        |    5 +
 .../scripts/toolkits/Gecko/braille_generator.py    |   10 +-
 src/orca/scripts/toolkits/Gecko/script.py          |  812 ++++++++++--------
 .../scripts/toolkits/Gecko/script_utilities.py     |   93 ++-
 .../scripts/toolkits/Gecko/speech_generator.py     |   16 +-
 .../toolkits/Gecko/structural_navigation.py        |    6 +-
 test/html/aria-alert-dialog.html                   |  650 +++++++++++++++
 test/html/aria-button-toggle.html                  |  400 +++++++++
 test/html/aria-radiobutton.html                    |  407 +++++++++
 test/html/aria-sliders.html                        |  869 ++++++++++++++++++++
 test/html/aria-tabpanel2.html                      |  769 +++++++++++++++++
 test/html/aria-tree.html                           |  672 +++++++++++++++
 test/html/iframes-inside-inline-block2.html        |   10 +
 test/html/radio-checked.gif                        |  Bin 0 -> 328 bytes
 test/html/radio-unchecked.gif                      |  Bin 0 -> 322 bytes
 test/html/slider_h-focus.png                       |  Bin 0 -> 3032 bytes
 test/html/slider_h.png                             |  Bin 0 -> 3066 bytes
 test/html/slider_v-focus.png                       |  Bin 0 -> 3016 bytes
 test/html/slider_v.png                             |  Bin 0 -> 3101 bytes
 test/html/treeContracted.gif                       |  Bin 0 -> 842 bytes
 test/html/treeContractedFocus.gif                  |  Bin 0 -> 842 bytes
 test/html/treeExpanded.gif                         |  Bin 0 -> 838 bytes
 test/html/treeExpandedFocus.gif                    |  Bin 0 -> 838 bytes
 test/keystrokes/firefox/aria_alert_dialog.params   |    1 +
 .../{aria_alert_uiuc.py => aria_alert_dialog.py}   |    0
 test/keystrokes/firefox/aria_alert_uiuc.params     |    1 -
 test/keystrokes/firefox/aria_button.py             |    6 +-
 test/keystrokes/firefox/aria_button_dojo.py        |  103 +--
 test/keystrokes/firefox/aria_button_toggle.params  |    1 +
 .../{aria_button_uiuc.py => aria_button_toggle.py} |   28 +-
 test/keystrokes/firefox/aria_button_uiuc.params    |    1 -
 test/keystrokes/firefox/aria_checkbox.py           |    8 -
 test/keystrokes/firefox/aria_combobox_dojo.py      |   73 +--
 test/keystrokes/firefox/aria_grid_uiuc.params      |    1 -
 test/keystrokes/firefox/aria_grid_uiuc.py          |   77 --
 test/keystrokes/firefox/aria_landmarks.py          |   48 +-
 test/keystrokes/firefox/aria_menu.py               |   36 +-
 .../firefox/aria_radio_button_uiuc.params          |    1 -
 test/keystrokes/firefox/aria_radiobutton.params    |    1 +
 ...ia_radio_button_uiuc.py => aria_radiobutton.py} |   32 +-
 test/keystrokes/firefox/aria_slider_dojo.py        |   27 +-
 test/keystrokes/firefox/aria_slider_tpg.py         |   58 +--
 test/keystrokes/firefox/aria_slider_uiuc.params    |    1 -
 test/keystrokes/firefox/aria_sliders.params        |    1 +
 .../{aria_slider_uiuc.py => aria_sliders.py}       |    7 +-
 test/keystrokes/firefox/aria_tabpanel.py           |    4 +
 test/keystrokes/firefox/aria_tabpanel2.params      |    1 +
 .../{aria_tabpanel_uiuc.py => aria_tabpanel2.py}   |   10 +-
 test/keystrokes/firefox/aria_tabpanel_uiuc.params  |    1 -
 test/keystrokes/firefox/aria_toolbar_dojo.py       |    2 +-
 test/keystrokes/firefox/aria_tree.params           |    1 +
 .../firefox/{aria_tree_uiuc.py => aria_tree.py}    |   14 +-
 test/keystrokes/firefox/aria_tree_dojo.py          |    1 +
 test/keystrokes/firefox/aria_tree_uiuc.params      |    1 -
 test/keystrokes/firefox/aria_treegrid.py           |   30 +-
 test/keystrokes/firefox/find_wiki.py               |   26 +-
 .../firefox/flat_review_hidden_elements.py         |    4 +
 .../keystrokes/firefox/flat_review_text_by_line.py |    4 +
 .../firefox/flat_review_text_by_word_and_char.py   |    4 +
 test/keystrokes/firefox/focus_tracking_imagemap.py |    6 +-
 test/keystrokes/firefox/html_page_summary.py       |    2 +-
 .../firefox/html_struct_nav_activate_link.py       |    2 +
 .../firefox/html_struct_nav_bug_554616.py          |   16 +-
 .../firefox/html_struct_nav_bug_567984.py          |    2 +
 .../firefox/html_struct_nav_descriptions.py        |    2 +
 .../html_struct_nav_heading_in_div_with_text.py    |    2 +
 .../html_struct_nav_headings_buried_deep.py        |    4 +
 test/keystrokes/firefox/html_struct_nav_links.py   |    2 +
 .../firefox/label_inference_bug_546815.py          |   12 +-
 .../firefox/label_inference_bugzilla_search.py     |   11 +
 test/keystrokes/firefox/label_inference_entries.py |    3 +-
 test/keystrokes/firefox/line_nav_bug_546815.py     |  105 +--
 test/keystrokes/firefox/line_nav_bug_549128.py     |    4 +
 test/keystrokes/firefox/line_nav_bug_552887a.py    |    4 +
 .../firefox/line_nav_bugzilla_search_down.py       |    4 +
 .../firefox/line_nav_bugzilla_search_up.py         |    4 +
 ...av_button_in_link_position_relative_on_focus.py |    3 +
 test/keystrokes/firefox/line_nav_clickables.py     |    4 +-
 test/keystrokes/firefox/line_nav_descriptions.py   |    3 +
 test/keystrokes/firefox/line_nav_empty_anchor.py   |    4 +
 test/keystrokes/firefox/line_nav_empty_textarea.py |    4 +
 test/keystrokes/firefox/line_nav_enter_bug.py      |   20 +-
 test/keystrokes/firefox/line_nav_entries.py        |   10 +-
 .../firefox/line_nav_follow_same_page_link_2.py    |   11 +-
 test/keystrokes/firefox/line_nav_hidden_label.py   |   30 +-
 .../firefox/line_nav_home_end_on_blank_line.py     |    5 +
 .../firefox/line_nav_iframes_in_inline_block.py    |    4 +
 .../line_nav_iframes_in_inline_block2.params       |    1 +
 .../firefox/line_nav_iframes_in_inline_block2.py   |  121 +++
 test/keystrokes/firefox/line_nav_image_in_link.py  |    4 +
 .../keystrokes/firefox/line_nav_images_in_links.py |    5 +-
 .../line_nav_link_position_relative_on_focus.py    |    4 +
 test/keystrokes/firefox/line_nav_lists.py          |    4 +
 .../keystrokes/firefox/line_nav_multi_line_text.py |    4 +
 test/keystrokes/firefox/line_nav_nested_tables.py  |    4 +
 test/keystrokes/firefox/line_nav_pre_lines.py      |    4 +
 test/keystrokes/firefox/line_nav_pre_links.py      |    4 +
 test/keystrokes/firefox/line_nav_simple_form.py    |   24 +-
 test/keystrokes/firefox/line_nav_slash_test.py     |    4 +
 test/keystrokes/firefox/line_nav_sun_java.py       |    5 +-
 .../firefox/line_nav_table_cell_links.py           |    4 +
 .../firefox/line_nav_textarea_last_line.params     |    1 +
 .../firefox/line_nav_textarea_last_line.py         |   36 +
 test/keystrokes/firefox/line_nav_wiki_down.py      |    4 +
 test/keystrokes/firefox/line_nav_wiki_up.py        |    4 +
 test/keystrokes/firefox/longdesc_1.py              |    6 +-
 test/keystrokes/firefox/longdesc_11.py             |   12 +-
 test/keystrokes/firefox/longdesc_12.py             |    5 +-
 test/keystrokes/firefox/longdesc_13.py             |    5 +-
 test/keystrokes/firefox/longdesc_14.py             |    6 +-
 test/keystrokes/firefox/longdesc_15.py             |    6 +-
 test/keystrokes/firefox/longdesc_2.py              |    6 +-
 test/keystrokes/firefox/longdesc_3.py              |    7 +-
 test/keystrokes/firefox/longdesc_7.py              |    2 -
 test/keystrokes/firefox/longdesc_8.py              |    7 +-
 test/keystrokes/firefox/longdesc_9.py              |    2 -
 .../firefox/object_nav_descriptions_down.py        |    4 +
 .../firefox/object_nav_descriptions_up.py          |    4 +
 .../firefox/object_nav_simple_form_down.py         |   16 +-
 .../firefox/object_nav_simple_form_up.py           |   14 +-
 test/keystrokes/firefox/say_all_entries.py         |    2 +-
 test/keystrokes/firefox/say_all_multi_line_text.py |    2 +
 test/keystrokes/firefox/say_all_simple_form.py     |    8 +-
 test/keystrokes/firefox/spelling_errors.py         |    4 +-
 test/keystrokes/firefox/ui_doc_tabs.py             |    4 +
 test/keystrokes/firefox/ui_role_accel_label.py     |    2 +-
 test/keystrokes/firefox/ui_role_list_item.py       |   10 +-
 test/keystrokes/firefox/ui_role_radio_button.py    |    4 +-
 test/keystrokes/firefox/ui_role_tree.py            |    2 +-
 test/keystrokes/firefox/ui_role_tree_table.py      |    6 +-
 test/keystrokes/firefox/word_nav_links.py          |    4 +
 137 files changed, 5002 insertions(+), 1114 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index df0b4bf..b19791f 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -325,6 +325,9 @@ formatting = {
                               + (expandableState and (expandableState + numberOfChildren))\
                               + required)'
             },
+        pyatspi.ROLE_TABLE_ROW: {
+            'focused': 'expandableState',
+            },
         pyatspi.ROLE_TEAROFF_MENU_ITEM: {
             'focused': '[]',
             'unfocused': 'labelOrName + allTextSelection + roleName + availability '
diff --git a/src/orca/scripts/apps/Thunderbird/Makefile.am b/src/orca/scripts/apps/Thunderbird/Makefile.am
index 2c3d82c..2e38f1a 100644
--- a/src/orca/scripts/apps/Thunderbird/Makefile.am
+++ b/src/orca/scripts/apps/Thunderbird/Makefile.am
@@ -1,6 +1,5 @@
 orca_python_PYTHON = \
        __init__.py \
-       formatting.py \
        script.py \
        script_utilities.py \
        speech_generator.py \
diff --git a/src/orca/scripts/apps/Thunderbird/script.py b/src/orca/scripts/apps/Thunderbird/script.py
index 434a6e7..baed062 100644
--- a/src/orca/scripts/apps/Thunderbird/script.py
+++ b/src/orca/scripts/apps/Thunderbird/script.py
@@ -38,7 +38,6 @@ import orca.speech as speech
 import orca.scripts.toolkits.Gecko as Gecko
 from orca.orca_i18n import _
 
-from .formatting import Formatting
 from .speech_generator import SpeechGenerator
 from .spellcheck import SpellCheck
 from .script_utilities import Utilities
@@ -79,10 +78,6 @@ class Script(Gecko.Script):
                 Script.togglePresentationMode,
                 cmdnames.TOGGLE_PRESENTATION_MODE)
 
-    def getFormatting(self):
-        """Returns the formatting strings for this script."""
-        return Formatting(self)
-
     def getSpeechGenerator(self):
         """Returns the speech generator for this script."""
 
diff --git a/src/orca/scripts/apps/Thunderbird/script_utilities.py 
b/src/orca/scripts/apps/Thunderbird/script_utilities.py
index 7623470..0cb4323 100644
--- a/src/orca/scripts/apps/Thunderbird/script_utilities.py
+++ b/src/orca/scripts/apps/Thunderbird/script_utilities.py
@@ -77,25 +77,3 @@ class Utilities(Gecko.Utilities):
                 obj = obj.parent
 
         return None
-
-    def isEntry(self, obj):
-        """Returns True if we should treat this object as an entry."""
-
-        return obj and obj.getRole() == pyatspi.ROLE_ENTRY
-
-    def isPasswordText(self, obj):
-        """Returns True if we should treat this object as password text."""
-
-        return obj and obj.getRole() == pyatspi.ROLE_PASSWORD_TEXT
-
-    #########################################################################
-    #                                                                       #
-    # Utilities for working with the accessible text interface              #
-    #                                                                       #
-    #########################################################################
-
-    #########################################################################
-    #                                                                       #
-    # Miscellaneous Utilities                                               #
-    #                                                                       #
-    #########################################################################
diff --git a/src/orca/scripts/apps/Thunderbird/speech_generator.py 
b/src/orca/scripts/apps/Thunderbird/speech_generator.py
index 7d77fbf..2c7b262 100644
--- a/src/orca/scripts/apps/Thunderbird/speech_generator.py
+++ b/src/orca/scripts/apps/Thunderbird/speech_generator.py
@@ -47,31 +47,6 @@ class SpeechGenerator(Gecko.SpeechGenerator):
     def __init__(self, script):
         Gecko.SpeechGenerator.__init__(self, script)
 
-    def _generateName(self, obj, **args):
-        """Returns an array of strings for use by speech and braille that
-        represent the name of the object. Overridden here because we do
-        not always want to treat displayed text as the name."""
-
-        result = []
-        if not self._script.isEditableMessage(obj):
-            result.extend(Gecko.SpeechGenerator._generateName(
-                    self, obj, **args))
-
-        return result
-
-    def _generateRoleName(self, obj, **args):
-        """Prevents some roles from being spoken."""
-        result = []
-        role = args.get('role', obj.getRole())
-        if role == pyatspi.ROLE_DOCUMENT_FRAME \
-           and obj.getState().contains(pyatspi.STATE_EDITABLE):
-            pass
-        else:
-            result.extend(Gecko.SpeechGenerator._generateRoleName(
-                              self, obj, **args))
-
-        return result
-
     def _generateColumnHeader(self, obj, **args):
         """Returns an array of strings (and possibly voice and audio
         specifications) that represent the column header for an object
diff --git a/src/orca/scripts/default.py b/src/orca/scripts/default.py
index 8964121..b7eaa92 100644
--- a/src/orca/scripts/default.py
+++ b/src/orca/scripts/default.py
@@ -741,6 +741,7 @@ class Script(script.Script):
 
         try:
             role = obj.getRole()
+            state = obj.getState()
         except:
             return
 
@@ -782,6 +783,9 @@ class Script(script.Script):
             self.pointOfReference['lastColumn'] = -1
             self.pointOfReference['lastRow'] = -1
 
+        self.pointOfReference['checkedChange'] = \
+            hash(obj), state.contains(pyatspi.STATE_CHECKED)
+
     def locusOfFocusChanged(self, event, oldLocusOfFocus, newLocusOfFocus):
         """Called when the visual object with focus changes.
 
@@ -2238,6 +2242,7 @@ class Script(script.Script):
         obj = event.source
         role = obj.getRole()
         if not self.utilities.isSameObject(obj, orca_state.locusOfFocus) \
+           and role != pyatspi.ROLE_TABLE_ROW \
            and not (role == pyatspi.ROLE_COMBO_BOX and event.detail1):
             return
 
diff --git a/src/orca/scripts/toolkits/Gecko/braille_generator.py 
b/src/orca/scripts/toolkits/Gecko/braille_generator.py
index eaeb61d..ccdb53b 100644
--- a/src/orca/scripts/toolkits/Gecko/braille_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/braille_generator.py
@@ -112,6 +112,10 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
     def _generateName(self, obj, **args):
         result = []
         role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_DOCUMENT_FRAME \
+           and obj.getState().contains(pyatspi.STATE_EDITABLE):
+            return []
+
         result.extend(braille_generator.BrailleGenerator._generateName(
                               self, obj, **args))
         if not result and role == pyatspi.ROLE_LIST_ITEM:
@@ -169,10 +173,8 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
         result = []
         args['includeContext'] = not self._script.inDocumentContent(obj)
         oldRole = None
-        if self._script.utilities.isEntry(obj):
-            oldRole = self._overrideRole(pyatspi.ROLE_ENTRY, args)
-        elif self._script.utilities.isClickableElement(obj) \
-             or self._script.utilities.isLink(obj):
+        if self._script.utilities.isClickableElement(obj) \
+           or self._script.utilities.isLink(obj):
             oldRole = self._overrideRole(pyatspi.ROLE_LINK, args)
 
         # Treat menu items in collapsed combo boxes as if the combo box
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index a88dc66..e88b407 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -2,7 +2,7 @@
 #
 # Copyright 2005-2009 Sun Microsystems Inc.
 # Copyright 2010 Orca Team.
-# Copyright 2014 Igalia, S.L.
+# Copyright 2014-2015 Igalia, S.L.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -35,7 +35,7 @@ __version__   = "$Revision$"
 __date__      = "$Date$"
 __copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc." \
                 "Copyright (c) 2010 Orca Team." \
-                "Copyright (c) 2014 Igalia, S.L."
+                "Copyright (c) 2014-2015 Igalia, S.L."
 __license__   = "LGPL"
 
 from gi.repository import Gtk
@@ -141,7 +141,6 @@ class Script(default.Script):
         # loading a page.
         #
         self._loadingDocumentContent = False
-        self._loadingDocumentTime = 0.0
 
         # In tabbed content (i.e., Firefox's support for one tab per
         # URL), we also keep track of the caret context in each tab.
@@ -161,12 +160,6 @@ class Script(default.Script):
         #
         self.madeFindAnnouncement = False
 
-        # We don't want to prevent the user from arrowing into an
-        # autocomplete when it appears in a search form.  We need to
-        # keep track if one has appeared or disappeared.
-        #
-        self._autocompleteVisible = False
-
         # Create the live region manager and start the message manager
         self.liveMngr = liveregions.LiveRegionManager(self)
 
@@ -182,12 +175,6 @@ class Script(default.Script):
         #
         self.currentAttrs = {}
 
-        # Last focused frame. We are only interested in frame focused events
-        # when it is a different frame, so here we store the last frame
-        # that recieved state-changed:focused.
-        #
-        self._currentFrame = None
-
         # A dictionary of Gecko-style attribute names and their equivalent/
         # expected names. This is necessary so that we can present the
         # attributes to the user in a consistent fashion across apps and
@@ -249,7 +236,6 @@ class Script(default.Script):
         self._inSayAll = False
         self._sayAllIsInterrupted = False
         self._loadingDocumentContent = False
-        self._loadingDocumentTime = 0.0
 
     def getBookmarks(self):
         """Returns the "bookmarks" class for this script.
@@ -904,344 +890,305 @@ class Script(default.Script):
         orca.setLocusOfFocus(None, context.obj, notifyScript=False)
         self.setCaretContext(context.obj, context.currentOffset)
 
-    def onCaretMoved(self, event):
-        """Callback for object:text-caret-moved accessibility events."""
-
-        if self.utilities.isZombie(event.source):
-            msg = "ERROR: Event source is Zombie"
-            debug.println(debug.LEVEL_INFO, msg)
-            return
+    def _getCtrlShiftSelectionsStrings(self):
+        return [messages.LINE_SELECTED_DOWN,
+                messages.LINE_UNSELECTED_DOWN,
+                messages.LINE_SELECTED_UP,
+                messages.LINE_UNSELECTED_UP]
 
-        if not self.inDocumentContent(event.source):
-            default.Script.onCaretMoved(self, event)
-            return
+    def onActiveChanged(self, event):
+        """Callback for object:state-changed:active accessibility events."""
 
-        if self._lastCommandWasCaretNav:
-            msg = "INFO: Caret-moved event ignored: last command was caret nav"
-            debug.println(debug.LEVEL_INFO, msg)
+        if self.findCommandRun:
+            self.findCommandRun = False
+            self.find()
             return
 
-        if self._lastCommandWasStructNav:
-            msg = "INFO: Caret-moved event ignored: last command was struct nav"
-            debug.println(debug.LEVEL_INFO, msg)
+        if not event.detail1:
             return
 
-        if self._lastCommandWasMouseButton:
+        role = event.source.getRole()
+        if role in [pyatspi.ROLE_DIALOG, pyatspi.ROLE_ALERT]:
             orca.setLocusOfFocus(event, event.source)
-            self.setCaretContext(event.source, event.detail1)
-            return
 
-        text = self.utilities.queryNonEmptyText(event.source)
-        if not text:
-            if event.source.getRole() == pyatspi.ROLE_LINK:
-                orca.setLocusOfFocus(event, event.source)
-                self.setCaretContext(event.source, event.detail1)
-            return
+    def onBusyChanged(self, event):
+        """Callback for object:state-changed:busy accessibility events."""
 
-        char, start, end = text.getTextAtOffset(event.detail1, pyatspi.TEXT_BOUNDARY_CHAR)
-        if char == self.EMBEDDED_OBJECT_CHARACTER:
-            msg = "INFO: Caret-moved event ignored: Caret moved to embedded object"
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
             debug.println(debug.LEVEL_INFO, msg)
-            return
+            super().onBusyChanged(event)
+            return False
 
-        if not char:
-            msg = "INFO: Caret-moved event ignored: Caret moved to empty character"
+        if not self.inDocumentContent(orca_state.locusOfFocus):
+            msg = "INFO: Ignoring: Locus of focus is not in document content"
             debug.println(debug.LEVEL_INFO, msg)
-            return
+            return True
 
-        contextObj, contextOffset = self.getCaretContext()
-        if event.detail1 == contextOffset and event.source == contextObj:
-            return
+        self._loadingDocumentContent = event.detail1
 
-        obj = event.source
-        state = obj.getState()
+        obj, offset = self.getCaretContext()
+        if not obj or self.utilities.isZombie(obj):
+            self.clearCaretContext()
 
-        firstObj, firstOffset = self.findFirstCaretContext(obj, event.detail1)
-        if firstOffset == contextOffset and firstObj == contextObj:
-            return
+        if not _settingsManager.getSetting('onlySpeakDisplayedText'):
+            if event.detail1:
+                msg = messages.PAGE_LOADING_START
+            elif event.source.name:
+                msg = messages.PAGE_LOADING_END_NAMED % event.source.name
+            else:
+                msg = messages.PAGE_LOADING_END
+            self.presentMessage(msg)
 
-        if contextObj and contextObj.parent == firstObj \
-           and not state.contains(pyatspi.STATE_EDITABLE):
-            return
+        if event.detail1:
+            return True
 
-        if self.utilities.inFindToolbar():
-            self.presentFindResults(obj, event.detail1)
-            return
+        if self.useFocusMode(orca_state.locusOfFocus) != self._inFocusMode:
+            self.togglePresentationMode(None)
 
-        self.setCaretContext(obj, event.detail1)
-        if not _settingsManager.getSetting('caretNavigationEnabled') \
-           or self._inFocusMode \
-           or state.contains(pyatspi.STATE_EDITABLE):
-            orca.setLocusOfFocus(event, obj, False)
+        obj, offset = self.getCaretContext()
+        if not obj:
+            msg = "INFO: Could not get caret context"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        default.Script.onCaretMoved(self, event)
+        if self.utilities.isFocusModeWidget(obj):
+            orca.setLocusOfFocus(event, obj)
+            return True
 
-    def onTextDeleted(self, event):
-        """Called whenever text is from an an object.
+        self.setCaretPosition(obj, offset)
+        contents = self.getLineContentsAtOffset(obj, offset)
+        self.updateBraille(obj)
+        if not _settingsManager.getSetting('sayAllOnLoad'):
+            self.speakContents(contents)
+        elif _settingsManager.getSetting('enableSpeech'):
+            self.sayAll(None)
 
-        Arguments:
-        - event: the Event
-        """
+        return True
 
-        self._destroyLineCache()
-        if not event.source.getState().contains(pyatspi.STATE_EDITABLE):
-            if self.inMouseOverObject:
-                obj = self.lastMouseOverObject
-                while obj and (obj != obj.parent):
-                    if self.utilities.isSameObject(event.source, obj):
-                        self.restorePreMouseOverContext()
-                        break
-                    obj = obj.parent
+    def onCaretMoved(self, event):
+        """Callback for object:text-caret-moved accessibility events."""
 
-        default.Script.onTextDeleted(self, event)
+        if self.utilities.isZombie(event.source):
+            msg = "ERROR: Event source is Zombie"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-    def onTextInserted(self, event):
-        """Called whenever text is inserted into an object.
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onCaretMoved(event)
+            return False
 
-        Arguments:
-        - event: the Event
-        """
-        self._destroyLineCache()
+        if self._lastCommandWasCaretNav:
+            msg = "INFO: Event ignored: Last command was caret nav"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        if self.handleAsLiveRegion(event):
-            self.liveMngr.handleEvent(event)
-            return
+        if self._lastCommandWasStructNav:
+            msg = "INFO: Event ignored: Last command was struct nav"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        default.Script.onTextInserted(self, event)
+        if self._lastCommandWasMouseButton:
+            msg = "INFO: Event handled: Last command was mouse button"
+            debug.println(debug.LEVEL_INFO, msg)
+            orca.setLocusOfFocus(event, event.source)
+            self.setCaretContext(event.source, event.detail1)
+            return True
 
-    def _getCtrlShiftSelectionsStrings(self):
-        return [messages.LINE_SELECTED_DOWN,
-                messages.LINE_UNSELECTED_DOWN,
-                messages.LINE_SELECTED_UP,
-                messages.LINE_UNSELECTED_UP]
+        if self.utilities.inFindToolbar() and not self.madeFindAnnouncement:
+            msg = "INFO: Event handled: Presenting find results"
+            debug.println(debug.LEVEL_INFO, msg)
+            self.presentFindResults(event.source, event.detail1)
+            return True
 
-    def onTextSelectionChanged(self, event):
-        """Called when an object's text selection changes.
+        if self.utilities.eventIsAutocompleteNoise(event):
+            msg = "INFO: Event ignored: Autocomplete noise"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        Arguments:
-        - event: the Event
-        """
+        if self.utilities.textEventIsForNonNavigableTextObject(event):
+            msg = "INFO: Event ignored: Event source is non-navigable text object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        if self.utilities.inFindToolbar():
-            self.presentFindResults(event.source, -1)
-            self._saveFocusedObjectInfo(orca_state.locusOfFocus)
-            return
+        if self.utilities.textEventIsDueToInsertion(event):
+            msg = "INFO: Event handled: Updating position due to insertion"
+            debug.println(debug.LEVEL_INFO, msg)
+            self._saveLastCursorPosition(event.source, event.detail1)
+            return True
 
-        if not self.inDocumentContent(orca_state.locusOfFocus) \
-           and self.inDocumentContent(event.source):
-            return
+        obj, offset = self.findFirstCaretContext(event.source, event.detail1)
 
-        if self.utilities.isZombie(event.source):
-            msg = "ERROR: Event source is Zombie"
+        if self.utilities.caretMovedToSamePageFragment(event):
+            msg = "INFO: Event handled: Caret moved to fragment"
             debug.println(debug.LEVEL_INFO, msg)
+            orca.setLocusOfFocus(event, obj)
+            self.setCaretContext(obj, offset)
             return True
 
         text = self.utilities.queryNonEmptyText(event.source)
         if not text:
-            msg = "INFO: Text-selection event ignored: There's no text"
-            debug.println(debug.LEVEL_INFO, msg)
-            return
+            if event.source.getRole() == pyatspi.ROLE_LINK:
+                msg = "INFO: Event handled: Was for non-text link"
+                debug.println(debug.LEVEL_INFO, msg)
+                orca.setLocusOfFocus(event, event.source)
+                self.setCaretContext(event.source, event.detail1)
+            else:
+                msg = "INFO: Event ignored: Was for non-text non-link"
+                debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        char, start, end = text.getTextAtOffset(text.caretOffset, pyatspi.TEXT_BOUNDARY_CHAR)
-        if char == self.EMBEDDED_OBJECT_CHARACTER:
-            msg = "INFO: Text-selection event ignored: Caret offset is at embedded object"
+        char = text.getText(event.detail1, event.detail1+1)
+        isEditable = obj.getState().contains(pyatspi.STATE_EDITABLE)
+        if not char and not isEditable:
+            msg = "INFO: Event ignored: Was for empty char in non-editable text"
             debug.println(debug.LEVEL_INFO, msg)
-            return
-
-        default.Script.onTextSelectionChanged(self, event)
-
-    def onActiveChanged(self, event):
-        """Callback for object:state-changed:active accessibility events."""
+            return True
 
-        if self.findCommandRun:
-            self.findCommandRun = False
-            self.find()
-            return
+        if char == self.EMBEDDED_OBJECT_CHARACTER:
+            if not self.utilities.isTextBlockElement(obj):
+                msg = "INFO: Event ignored: Was for embedded non-textblock"
+                debug.println(debug.LEVEL_INFO, msg)
+                return True
 
-        if not event.detail1:
-            return
+            msg = "INFO: Setting locusOfFocus, context to: %s, %i" % (obj, offset)
+            debug.println(debug.LEVEL_INFO, msg)
+            orca.setLocusOfFocus(event, obj)
+            self.setCaretContext(obj, offset)
+            return True
 
-        role = event.source.getRole()
-        if role in [pyatspi.ROLE_DIALOG, pyatspi.ROLE_ALERT]:
-            orca.setLocusOfFocus(event, event.source)
+        if not _settingsManager.getSetting('caretNavigationEnabled') \
+           or self._inFocusMode or isEditable:
+            orca.setLocusOfFocus(event, event.source, False)
+            self.setCaretContext(event.source, event.detail1)
+            msg = "INFO: Setting locusOfFocus, context to: %s, %i" % \
+                  (event.source, event.detail1)
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onCaretMoved(event)
+            return False
 
-    def onBusyChanged(self, event):
-        """Callback for object:state-changed:busy accessibility events."""
+        self.setCaretContext(obj, offset)
+        msg = "INFO: Setting context to: %s, %i" % (obj, offset)
+        debug.println(debug.LEVEL_INFO, msg)
+        super().onCaretMoved(event)
+        return False
 
-        try:
-            obj = event.source
-            role = obj.getRole()
-            name = obj.name
-        except:
-            return
-        if role != pyatspi.ROLE_DOCUMENT_FRAME:
-             return
+    def onCheckedChanged(self, event):
+        """Callback for object:state-changed:checked accessibility events."""
 
-        try:
-            focusRole = orca_state.locusOfFocus.getRole()
-        except:
-            focusRole = None
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onCheckedChanged(event)
+            return False
 
-        # The event is for the changing contents of the help frame as the user
-        # navigates from topic to topic in the list on the left. Ignore this.
-        if focusRole == pyatspi.ROLE_LIST_ITEM \
-           and not self.inDocumentContent(orca_state.locusOfFocus):
-            return
+        obj, offset = self.getCaretContext()
+        if obj != event.source:
+            msg = "INFO: Event source is not context object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        self._loadingDocumentContent = event.detail1
-        finishedLoading = False
-        if event.detail1:
-            message = messages.PAGE_LOADING_START
-        elif name:
-            message = messages.PAGE_LOADING_END_NAMED % name
-            finishedLoading = True
-        else:
-            message = messages.PAGE_LOADING_END
-            finishedLoading = True
- 
-        if not _settingsManager.getSetting('onlySpeakDisplayedText'):
-            self.presentMessage(message)
- 
-        if not finishedLoading:
-            return
+        oldObj, oldState = self.pointOfReference.get('checkedChange', (None, 0))
+        if hash(oldObj) == hash(obj) and oldState == event.detail1:
+            msg = "INFO: Ignoring event, state hasn't changed"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
-        if self.useFocusMode(orca_state.locusOfFocus) != self._inFocusMode:
-            self.togglePresentationMode(None)
+        role = obj.getRole()
+        if not (self._lastCommandWasCaretNav and role == pyatspi.ROLE_RADIO_BUTTON):
+            msg = "INFO: Event is something default can handle"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onCheckedChanged(event)
+            return False
 
-        # Store the document frame otherwise the first time it gains focus (e.g.
-        # the first time the user arrows off of a link into non-focusable text),
-        # onFocused will start chatting unnecessarily.
-        self._currentFrame = obj
- 
-        # First try to figure out where the caret is on the newly loaded page.
-        # If it is on an editable object (e.g., a text entry), then present just
-        # that object. Otherwise, force the caret to the top of the page and
-        # start a SayAll from that position.
-        [obj, characterOffset] = self.getCaretContext()
-        atTop = False
-        if not obj:
-            self.clearCaretContext()
-            [obj, characterOffset] = self.getCaretContext()
-            atTop = True
-        if not obj:
-             return
-        if not atTop and not obj.getState().contains(pyatspi.STATE_FOCUSABLE):
-            self.clearCaretContext()
-            [obj, characterOffset] = self.getCaretContext()
-            if not obj:
-                return
- 
-        # For braille, we just show the current line containing the caret. For
-        # speech, however, we will start a Say All operation if the caret is in
-        # an unfocusable area (e.g., it's not in a text entry area such as
-        # Google's search text entry or a link that we just returned to by
-        # pressing the back button). Otherwise, we'll just speak the line that
-        # the caret is on.
         self.updateBraille(obj)
-        if obj.getState().contains(pyatspi.STATE_FOCUSABLE):
-            speech.speak(self.speechGenerator.generateSpeech(obj))
-        elif not _settingsManager.getSetting('sayAllOnLoad'):
-            self.speakContents(
-                self.getLineContentsAtOffset(obj, characterOffset))
-        elif _settingsManager.getSetting('enableSpeech'):
-            self.sayAll(None)
+        speech.speak(self.speechGenerator.generateSpeech(obj, alreadyFocused=True))
+        self.pointOfReference['checkedChange'] = hash(obj), event.detail1
+        return True
 
     def onChildrenChanged(self, event):
         """Callback for object:children-changed accessibility events."""
 
-        if event.any_data is None:
-            return
+        if self.handleAsLiveRegion(event):
+            msg = "INFO: Event to be handled as live region"
+            debug.println(debug.LEVEL_INFO, msg)
+            self.liveMngr.handleEvent(event)
+            return True
 
-        if not event.type.startswith("object:children-changed:add"):
-            return
+        if self._loadingDocumentContent:
+            msg = "INFO: Ignoring because document content is being loaded."
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if not event.any_data or self.utilities.isZombie(event.any_data):
+            msg = "INFO: Ignoring because any data is null or zombified."
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onChildrenChanged(event)
+            return False
 
-        # Certain Web Dev practices, such as a:focus{position:relative;}, cause
-        # Gecko to kill the accessible object that we just moved to and create
-        # a new object to replace it. If we don't catch this, navigation breaks
-        # because the proverbial rug has just been pulled out from under us. :(
-        # To make matters worse, the replacement object can be in the ancestry.
         obj, offset = self.getCaretContext()
-        if obj and self.utilities.isZombie(obj) and not self._loadingDocumentContent:
+        if obj and self.utilities.isZombie(obj):
             replicant = self.utilities.findReplicant(event.source, obj)
             if replicant:
                 # Refrain from actually touching the replicant by grabbing
                 # focus or setting the caret in it. Doing so will only serve
                 # to anger it.
+                msg = "INFO: Event handled by updating locusOfFocus and context"
+                debug.println(debug.LEVEL_INFO, msg)
                 orca.setLocusOfFocus(event, replicant, False)
                 self.setCaretContext(replicant, offset)
-                return
-
-        if self.handleAsLiveRegion(event):
-            self.liveMngr.handleEvent(event)
-            return
+                return True
 
         child = event.any_data
-        try:
-            childRole = child.getRole()
-        except:
-            return
-
-        if childRole == pyatspi.ROLE_ALERT:
+        if child.getRole() in [pyatspi.ROLE_ALERT, pyatspi.ROLE_DIALOG]:
+            msg = "INFO: Setting locusOfFocus to event.any_data"
+            debug.println(debug.LEVEL_INFO, msg)
             orca.setLocusOfFocus(event, child)
-            return
-
-        if childRole == pyatspi.ROLE_DIALOG:
-            if self.inDocumentContent(event.source):
-                orca.setLocusOfFocus(event, child)
-            return
+            return True
 
-        if self.lastMouseRoutingTime \
-           and 0 < time.time() - self.lastMouseRoutingTime < 1:
+        if self.lastMouseRoutingTime and 0 < time.time() - self.lastMouseRoutingTime < 1:
             utterances = []
             utterances.append(messages.NEW_ITEM_ADDED)
-            utterances.extend(
-                self.speechGenerator.generateSpeech(child, force=True))
+            utterances.extend(self.speechGenerator.generateSpeech(child, force=True))
             speech.speak(utterances)
             self.lastMouseOverObject = child
             self.preMouseOverContext = self.getCaretContext()
-            return
-
-        default.Script.onChildrenChanged(self, event)
-
-    def onDocumentReload(self, event):
-        """Callback for document:reload accessibility events."""
+            return True
 
-        # We care about the main document and we'll ignore document
-        # events from HTML iframes.
-        #
-        if event.source.getRole() == pyatspi.ROLE_DOCUMENT_FRAME:
-            self._loadingDocumentContent = True
+        super().onChildrenChanged(event)
+        return False
 
     def onDocumentLoadComplete(self, event):
         """Callback for document:load-complete accessibility events."""
 
-        # We care about the main document and we'll ignore document
-        # events from HTML iframes.
-        #
-        if event.source.getRole() == pyatspi.ROLE_DOCUMENT_FRAME:
-            # Reset the live region manager.
-            self.liveMngr.reset()
-            self._loadingDocumentContent = False
-            self._loadingDocumentTime = time.time()
+        msg = "INFO: Updating loading state and resetting live regions"
+        debug.println(debug.LEVEL_INFO, msg)
+        self._loadingDocumentContent = False
+        self.liveMngr.reset()
+        return True
 
     def onDocumentLoadStopped(self, event):
         """Callback for document:load-stopped accessibility events."""
 
-        # We care about the main document and we'll ignore document
-        # events from HTML iframes.
-        #
-        if event.source.getRole() == pyatspi.ROLE_DOCUMENT_FRAME:
-            self._loadingDocumentContent = False
-            self._loadingDocumentTime = time.time()
+        msg = "INFO: Updating loading state"
+        debug.println(debug.LEVEL_INFO, msg)
+        self._loadingDocumentContent = False
+        return True
 
-    def onNameChanged(self, event):
-        """Called whenever a property on an object changes.
+    def onDocumentReload(self, event):
+        """Callback for document:reload accessibility events."""
 
-        Arguments:
-        - event: the Event
-        """
-        if event.source.getRole() == pyatspi.ROLE_FRAME:
-            self.liveMngr.flushMessages()
+        msg = "INFO: Updating loading state"
+        debug.println(debug.LEVEL_INFO, msg)
+        self._loadingDocumentContent = True
+        return True
 
     def onFocus(self, event):
         """Callback for focus: accessibility events."""
@@ -1281,60 +1228,73 @@ class Script(default.Script):
         """Callback for object:state-changed:focused accessibility events."""
 
         if not event.detail1:
-            return
+            msg = "INFO: Ignoring because event source lost focus"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
         if self.utilities.isZombie(event.source):
             msg = "ERROR: Event source is Zombie"
             debug.println(debug.LEVEL_INFO, msg)
-            return
-
-        if not _settingsManager.getSetting('caretNavigationEnabled'):
-            default.Script.onFocusedChanged(self, event)
-            return
+            return True
 
-        obj = event.source
-        if not self.inDocumentContent(obj):
-            default.Script.onFocusedChanged(self, event)
-            return
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onFocusedChanged(event)
+            return False
 
-        state = obj.getState()
+        state = event.source.getState()
         if state.contains(pyatspi.STATE_EDITABLE):
-            default.Script.onFocusedChanged(self, event)
-            return
+            msg = "INFO: Event source is editable"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onFocusedChanged(event)
+            return False
 
-        role = obj.getRole()
+        role = event.source.getRole()
         if role in [pyatspi.ROLE_DIALOG, pyatspi.ROLE_ALERT]:
+            msg = "INFO: Event handled: Setting locusOfFocus to event source"
+            debug.println(debug.LEVEL_INFO, msg)
             orca.setLocusOfFocus(event, event.source)
-            return
-
-        # As the caret moves into a non-focusable element, Gecko emits the
-        # signal on the first focusable element in the ancestry.
-        rolesToIgnore = pyatspi.ROLE_DOCUMENT_FRAME, pyatspi.ROLE_PANEL
-        if role in rolesToIgnore:
-            if self.inDocumentContent():
-                return
-
-            contextObj, contextOffset = self.getCaretContext()
-            if contextObj:
-                orca.setLocusOfFocus(event, contextObj)
-                return
+            return True
 
-        # If we caused this event, we don't want to double-present it.
         if self._lastCommandWasCaretNav:
-            msg = "INFO: Focus change event ignored: last command was caret nav"
+            msg = "INFO: Event ignored: Last command was caret nav"
             debug.println(debug.LEVEL_INFO, msg)
-            return
+            return True
 
         if self._lastCommandWasStructNav:
-            msg = "INFO: Focus change event handled manually: last command was struct nav"
+            msg = "INFO: Event ignored: Last command was struct nav"
             debug.println(debug.LEVEL_INFO, msg)
-            if role != pyatspi.ROLE_LINK \
-               and obj.parent.getRole() != pyatspi.ROLE_LIST_BOX:
-                self.setCaretContext(event.source, 0)
-                orca.setLocusOfFocus(event, event.source)
-            return
+            return True
 
-        default.Script.onFocusedChanged(self, event)
+        if role in [pyatspi.ROLE_DOCUMENT_FRAME, pyatspi.ROLE_DOCUMENT_WEB]:
+            if self.inDocumentContent(orca_state.locusOfFocus) \
+               and not self.utilities.isZombie(orca_state.locusOfFocus):
+                msg = "INFO: Event ignored: locusOfFocus already in document"
+                debug.println(debug.LEVEL_INFO, msg)
+                return True
+
+            obj, offset = self.getCaretContext(event.source)
+            if obj and self.utilities.isZombie(obj):
+                msg = "INFO: Clearing context - obj is zombie"
+                debug.println(debug.LEVEL_INFO, msg)
+                self.clearCaretContext()
+                obj, offset = self.getCaretContext(event.source)
+
+            if obj:
+                msg = "INFO: Event handled: Setting locusOfFocus to context"
+                debug.println(debug.LEVEL_INFO, msg)
+                orca.setLocusOfFocus(event, obj)
+                return True
+
+        if not state.contains(pyatspi.STATE_FOCUSABLE) \
+           and not state.contains(pyatspi.STATE_FOCUSED):
+            msg = "INFO: Event ignored: Source is not focusable or focused"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        super().onFocusedChanged(event)
+        return False
 
     def onMouseButton(self, event):
         """Callback for mouse:button accessibility events."""
@@ -1342,42 +1302,171 @@ class Script(default.Script):
         self._lastCommandWasCaretNav = False
         self._lastCommandWasStructNav = False
         self._lastCommandWasMouseButton = True
-        default.Script.onMouseButton(self, event)
+        super().onMouseButton(event)
+        return False
+
+    def onNameChanged(self, event):
+        """Callback for object:property-change:accessible-name events."""
+
+        if event.source.getRole() == pyatspi.ROLE_FRAME:
+            msg = "INFO: Flusing messages from live region manager"
+            debug.println(debug.LEVEL_INFO, msg)
+            self.liveMngr.flushMessages()
+
+        return True
 
     def onShowingChanged(self, event):
         """Callback for object:state-changed:showing accessibility events."""
 
-        # TODO - JD: Once there are separate scripts for the Gecko toolkit
-        # and the Firefox browser, the stuff below belongs in the browser
-        # script and not in the toolkit script.
- 
-        try:
-            eventRole = event.source.getRole()
-            focusedRole = orca_state.locusOfFocus.getRole()
-        except:
-            default.Script.onShowingChanged(self, event)
-            return
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onShowingChanged(event)
+            return False
 
-        # If an autocomplete appears beneath an entry, we don't want
-        # to prevent the user from being able to arrow into it.
-        if eventRole == pyatspi.ROLE_WINDOW \
-           and focusedRole in [pyatspi.ROLE_ENTRY, pyatspi.ROLE_LIST_ITEM]:
-            self._autocompleteVisible = event.detail1
-            # If the autocomplete has just appeared, we want to speak
-            # its appearance if the user's verbosity level is verbose
-            # or if the user forced it to appear with (Alt+)Down Arrow.
-            if self._autocompleteVisible:
-                level = _settingsManager.getSetting('speechVerbosityLevel')
-                speakIt = level == settings.VERBOSITY_LEVEL_VERBOSE
-                if not speakIt:
-                    eventString, mods = self.utilities.lastKeyAndModifiers()
-                    speakIt = eventString == "Down"
-                if speakIt:
-                    speech.speak(self.speechGenerator.getLocalizedRoleName(
-                        event.source, pyatspi.ROLE_AUTOCOMPLETE))
-                    return
+        return True
+
+    def onTextDeleted(self, event):
+        """Callback for object:text-changed:delete accessibility events."""
 
-        default.Script.onShowingChanged(self, event)
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onTextDeleted(event)
+            return False
+
+        if self.utilities.eventIsAutocompleteNoise(event):
+            msg = "INFO: Ignoring event believed to be autocomplete noise"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if self.utilities.textEventIsDueToInsertion(event):
+            msg = "INFO: Ignoring event believed to be due to text insertion"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        msg = "INFO: Clearing content cache due to text deletion"
+        debug.println(debug.LEVEL_INFO, msg)
+        # self.utilities.clearContentCache()
+        self._destroyLineCache()
+
+        state = event.source.getState()
+        if not state.contains(pyatspi.STATE_EDITABLE):
+            if self.inMouseOverObject \
+               and self.utilities.isZombie(self.lastMouseOverObject):
+                msg = "INFO: Restoring pre-mouseover context"
+                debug.println(debug.LEVEL_INFO, msg)
+                self.restorePreMouseOverContext()
+
+            msg = "INFO: Done processing non-editable source"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        super().onTextDeleted(event)
+        return False
+
+    def onTextInserted(self, event):
+        """Callback for object:text-changed:insert accessibility events."""
+
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onTextInserted(event)
+            return False
+
+        if self.utilities.eventIsAutocompleteNoise(event):
+            msg = "INFO: Ignoring: Event believed to be autocomplete noise"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        msg = "INFO: Clearing content cache due to text insertion"
+        debug.println(debug.LEVEL_INFO, msg)
+        # self.utilities.clearContentCache()
+        self._destroyLineCache()
+
+        if self.handleAsLiveRegion(event):
+            msg = "INFO: Event to be handled as live region"
+            debug.println(debug.LEVEL_INFO, msg)
+            self.liveMngr.handleEvent(event)
+            return True
+
+        if self.utilities.eventIsEOCAdded(event):
+            msg = "INFO: Ignoring: Event was for embedded object char"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        text = self.utilities.queryNonEmptyText(event.source)
+        if not text:
+            msg = "INFO: Ignoring: Event source is not a text object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        state = event.source.getState()
+        if not state.contains(pyatspi.STATE_EDITABLE) \
+           and event.source != orca_state.locusOfFocus:
+            msg = "INFO: Done processing non-editable, non-locusOfFocus source"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        super().onTextInserted(event)
+        return False
+
+    def onTextSelectionChanged(self, event):
+        """Callback for object:text-selection-changed accessibility events."""
+
+        if self.utilities.isZombie(event.source):
+            msg = "ERROR: Event source is Zombie"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if not self.inDocumentContent(event.source):
+            msg = "INFO: Event source is not in document content"
+            debug.println(debug.LEVEL_INFO, msg)
+            super().onTextSelectionChanged(event)
+            return False
+
+        if self.utilities.inFindToolbar():
+            msg = "INFO: Event handled: Presenting find results"
+            debug.println(debug.LEVEL_INFO, msg)
+            self.presentFindResults(event.source, -1)
+            self._saveFocusedObjectInfo(orca_state.locusOfFocus)
+            return True
+
+        if not self.inDocumentContent(orca_state.locusOfFocus):
+            msg = "INFO: Ignoring: Event in document content; focus is not"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if self.utilities.eventIsAutocompleteNoise(event):
+            msg = "INFO: Ignoring: Event believed to be autocomplete noise"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        if self.utilities.textEventIsForNonNavigableTextObject(event):
+            msg = "INFO: Ignoring event for non-navigable text object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        text = self.utilities.queryNonEmptyText(event.source)
+        if not text:
+            msg = "INFO: Ignoring: Event source is not a text object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        char = text.getText(event.detail1, event.detail1+1)
+        if char == self.EMBEDDED_OBJECT_CHARACTER:
+            msg = "INFO: Ignoring: Event offset is at embedded object"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        obj, offset = self.getCaretContext()
+        if obj and obj.parent and event.source in [obj.parent, obj.parent.parent]:
+            msg = "INFO: Ignoring: Source is context ancestor"
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
+
+        super().onTextSelectionChanged(event)
+        return False
 
     def handleProgressBarUpdate(self, event, obj):
         """Determine whether this progress bar event should be spoken or not.
@@ -1412,25 +1501,20 @@ class Script(default.Script):
         return self.utilities.isFocusModeWidget(obj)
 
     def locusOfFocusChanged(self, event, oldFocus, newFocus):
-        """Called when the object with focus changes.
-
-        Arguments:
-        - event: if not None, the Event that caused the change
-        - oldFocus: Accessible that is the old focus
-        - newFocus: Accessible that is the new focus
-        """
+        """Handles changes of focus of interest to the script."""
 
-        if not newFocus:
-            orca_state.noFocusTimeStamp = time.time()
-            return
-
-        if self.utilities.inFindToolbar(newFocus):
-            self.madeFindAnnouncement = False
+        if newFocus and self.utilities.isZombie(newFocus):
+            msg = "ERROR: New focus is Zombie" % newFocus
+            debug.println(debug.LEVEL_INFO, msg)
+            return True
 
         if not self.inDocumentContent(newFocus):
-            default.Script.locusOfFocusChanged(self, event, oldFocus, newFocus)
+            msg = "INFO: Locus of focus changed to non-document obj"
+            self._madeFindAnnouncement = False
             self._inFocusMode = False
-            return
+            debug.println(debug.LEVEL_INFO, msg)
+            super().locusOfFocusChanged(event, oldFocus, newFocus)
+            return False
 
         caretOffset = -1
         if self.utilities.inFindToolbar(oldFocus):
@@ -1441,14 +1525,16 @@ class Script(default.Script):
             caretOffset = text.caretOffset
 
         self.setCaretContext(newFocus, caretOffset)
-        default.Script.locusOfFocusChanged(self, event, oldFocus, newFocus)
+        self.updateBraille(newFocus)
+        speech.speak(self.speechGenerator.generateSpeech(newFocus, priorObj=oldFocus))
+        self._saveFocusedObjectInfo(newFocus)
 
-        if self._focusModeIsSticky:
-            return
-
-        if self.useFocusMode(newFocus) != self._inFocusMode:
+        if not self._focusModeIsSticky \
+           and self.useFocusMode(newFocus) != self._inFocusMode:
             self.togglePresentationMode(None)
 
+        return True
+
     def _destroyLineCache(self):
         """Removes all of the stored lines."""
 
@@ -1549,7 +1635,7 @@ class Script(default.Script):
         # things, however, we can defer to the default scripts.
         #
 
-        if not self.inDocumentContent() or self.utilities.isEntry(obj):
+        if not self.inDocumentContent() or obj.getState().contains(pyatspi.STATE_EDITABLE):
             default.Script.sayCharacter(self, obj)
             return
 
@@ -1564,7 +1650,7 @@ class Script(default.Script):
         # EMBEDDED_OBJECT_CHARACTER model of Gecko.  For all other
         # things, however, we can defer to the default scripts.
         #
-        if not self.inDocumentContent() or self.utilities.isEntry(obj):
+        if not self.inDocumentContent() or obj.getState().contains(pyatspi.STATE_EDITABLE):
             default.Script.sayWord(self, obj)
             return
 
@@ -1582,7 +1668,7 @@ class Script(default.Script):
         # EMBEDDED_OBJECT_CHARACTER model of Gecko.  For all other
         # things, however, we can defer to the default scripts.
         #
-        if not self.inDocumentContent() or self.utilities.isEntry(obj):
+        if not self.inDocumentContent() or obj.getState().contains(pyatspi.STATE_EDITABLE):
             default.Script.sayLine(self, obj)
             return
 
@@ -2237,8 +2323,7 @@ class Script(default.Script):
         """To-be-removed. Returns the string, caretOffset, startOffset."""
 
         if self._inFocusMode or not self.inDocumentContent(obj) \
-           or self.utilities.isEntry(obj) \
-           or self.utilities.isPasswordText(obj):
+           or obj.getState().contains(pyatspi.STATE_EDITABLE):
             return super().getTextLineAtCaret(obj, offset, startOffset, endOffset)
 
         text = self.utilities.queryNonEmptyText(obj)
@@ -2430,7 +2515,7 @@ class Script(default.Script):
         if obj:
             if character and character != self.EMBEDDED_OBJECT_CHARACTER:
                 self.speakCharacter(character)
-            elif not self.utilities.isEntry(obj):
+            elif not obj.getState().contains(pyatspi.STATE_EDITABLE):
                 # We won't have a character if we move to the end of an
                 # entry (in which case we're not on a character and therefore
                 # have nothing to say), or when we hit a component with no
@@ -2475,6 +2560,9 @@ class Script(default.Script):
         if self.useFocusMode(obj) != self._inFocusMode:
             self.togglePresentationMode(None)
 
+        obj.clearCache()
+        self._saveFocusedObjectInfo(obj)
+
     def moveToMouseOver(self, inputEvent):
         """Positions the caret offset to the next character or object
         in the mouse over which has just appeared.
diff --git a/src/orca/scripts/toolkits/Gecko/script_utilities.py 
b/src/orca/scripts/toolkits/Gecko/script_utilities.py
index 9d3e4dd..dd19501 100644
--- a/src/orca/scripts/toolkits/Gecko/script_utilities.py
+++ b/src/orca/scripts/toolkits/Gecko/script_utilities.py
@@ -1,7 +1,7 @@
 # Orca
 #
 # Copyright 2010 Joanmarie Diggs.
-# Copyright 2014 Igalia, S.L.
+# Copyright 2014-2015 Igalia, S.L.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -27,13 +27,14 @@ __id__ = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
 __copyright__ = "Copyright (c) 2010 Joanmarie Diggs." \
-                "Copyright (c) 2014 Igalia, S.L."
+                "Copyright (c) 2014-2015 Igalia, S.L."
 __license__   = "LGPL"
 
 import pyatspi
 import re
 
 import orca.debug as debug
+import orca.input_event as input_event
 import orca.orca_state as orca_state
 import orca.script_utilities as script_utilities
 
@@ -165,23 +166,6 @@ class Utilities(script_utilities.Utilities):
 
         return script_utilities.Utilities.inFindToolbar(obj)
 
-    def isEntry(self, obj):
-        """Returns True if we should treat this object as an entry."""
-
-        if not obj:
-            return False
-
-        if obj.getRole() == pyatspi.ROLE_ENTRY:
-            return True
-
-        if obj.getState().contains(pyatspi.STATE_EDITABLE) \
-           and obj.getRole() in [pyatspi.ROLE_DOCUMENT_FRAME,
-                                 pyatspi.ROLE_PARAGRAPH,
-                                 pyatspi.ROLE_TEXT]:
-            return True
-
-        return False
-
     def isLink(self, obj):
         """Returns True if we should treat this object as a link."""
 
@@ -199,11 +183,6 @@ class Utilities(script_utilities.Utilities):
 
         return False
 
-    def isPasswordText(self, obj):
-        """Returns True if we should treat this object as password text."""
-
-        return obj and obj.getRole() == pyatspi.ROLE_PASSWORD_TEXT
-
     def isHidden(self, obj):
         attrs = dict([attr.split(':', 1) for attr in obj.getAttributes()])
         isHidden = attrs.get('hidden', False)
@@ -519,6 +498,7 @@ class Utilities(script_utilities.Utilities):
     def _treatTextObjectAsWhole(self, obj):
         roles = [pyatspi.ROLE_CHECK_BOX,
                  pyatspi.ROLE_CHECK_MENU_ITEM,
+                 pyatspi.ROLE_MENU,
                  pyatspi.ROLE_MENU_ITEM,
                  pyatspi.ROLE_RADIO_MENU_ITEM,
                  pyatspi.ROLE_RADIO_BUTTON,
@@ -529,6 +509,9 @@ class Utilities(script_utilities.Utilities):
         if role in roles:
             return True
 
+        if role == pyatspi.ROLE_TABLE_CELL and self.isFocusModeWidget(obj):
+            return True
+
         return False
 
     def __findRange(self, obj, offset, boundary):
@@ -1184,3 +1167,65 @@ class Utilities(script_utilities.Utilities):
                 return True
 
         return False
+
+    def eventIsAutocompleteNoise(self, event):
+        if not self._script.inDocumentContent(event.source):
+            return False
+
+        isListBoxItem = lambda x: x and x.parent.getRole() == pyatspi.ROLE_LIST_BOX
+        isMenuItem = lambda x: x and x.parent.getRole() == pyatspi.ROLE_MENU
+        isComboBoxItem = lambda x: x and x.parent.getRole() == pyatspi.ROLE_COMBO_BOX
+
+        if event.source.getState().contains(pyatspi.STATE_EDITABLE) \
+           and event.type.startswith("object:text-"):
+            obj, offset = self._script.getCaretContext()
+            if isListBoxItem(obj) or isMenuItem(obj):
+                return True
+
+            if obj == event.source and isComboBoxItem(obj):
+                lastKey, mods = self.lastKeyAndModifiers()
+                if lastKey in ["Down", "Up"]:
+                    return True
+
+        return False
+
+    def textEventIsDueToInsertion(self, event):
+        if not event.type.startswith("object:text-"):
+            return False
+
+        if not self._script.inDocumentContent(event.source) \
+           or not event.source.getState().contains(pyatspi.STATE_EDITABLE) \
+           or not event.source == orca_state.locusOfFocus:
+            return False
+
+        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
+            inputEvent = orca_state.lastNonModifierKeyEvent
+            return inputEvent and inputEvent.isPrintableKey()
+
+        return False
+
+    def textEventIsForNonNavigableTextObject(self, event):
+        if not event.type.startswith("object:text-"):
+            return False
+
+        return self._treatTextObjectAsWhole(event.source)
+
+    def eventIsEOCAdded(self, event):
+        if not self._script.inDocumentContent(event.source):
+            return False
+
+        if event.type.startswith("object:text-changed:insert"):
+            return event.any_data == self.EMBEDDED_OBJECT_CHARACTER
+
+        return False
+
+    def caretMovedToSamePageFragment(self, event):
+        if not event.type.startswith("object:text-caret-moved"):
+            return False
+
+        linkURI = self.uri(orca_state.locusOfFocus)
+        docURI = self.documentFrameURI()
+        if linkURI == docURI:
+            return True
+
+        return False
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py 
b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index 8d2e92a..67bafb1 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -71,6 +71,10 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         result = []
         acss = self.voice(speech_generator.DEFAULT)
         role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_DOCUMENT_FRAME \
+           and obj.getState().contains(pyatspi.STATE_EDITABLE):
+            return []
+
         result.extend(speech_generator.SpeechGenerator._generateName(
                               self, obj, **args))
         if not result and role == pyatspi.ROLE_LIST_ITEM:
@@ -174,6 +178,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
            and not self._script.utilities.isTextBlockElement(obj) \
            and not self._script.utilities.isLink(obj):
             return []
+        if role == pyatspi.ROLE_DOCUMENT_FRAME \
+           and obj.getState().contains(pyatspi.STATE_EDITABLE):
+            return []
 
         if not force:
             doNotSpeak = [pyatspi.ROLE_FORM,
@@ -285,6 +292,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
                                pyatspi.ROLE_TOOL_BAR]
         args['skipRoles'] = [pyatspi.ROLE_PARAGRAPH,
                              pyatspi.ROLE_LIST_ITEM,
+                             pyatspi.ROLE_TABLE_ROW,
                              pyatspi.ROLE_TEXT]
 
         return speech_generator.SpeechGenerator._generateAncestors(
@@ -345,11 +353,6 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             result.extend(speech_generator.SpeechGenerator.\
                                            generateSpeech(self, obj, **args))
             self._restoreRole(oldRole, args)
-        elif self._script.utilities.isEntry(obj):
-            oldRole = self._overrideRole(pyatspi.ROLE_ENTRY, args)
-            result.extend(speech_generator.SpeechGenerator.\
-                                           generateSpeech(self, obj, **args))
-            self._restoreRole(oldRole, args)
         elif self._script.utilities.isLink(obj):
             oldRole = self._overrideRole(pyatspi.ROLE_LINK, args)
             result.extend(speech_generator.SpeechGenerator.\
@@ -440,8 +443,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         if not string:
             return []
 
-        if not self._script.utilities.isEntry(obj) \
-           and not self._script.utilities.isPasswordText(obj):
+        if not obj.getState().contains(pyatspi.STATE_EDITABLE):
             string = string.strip()
 
         result = [string]
diff --git a/src/orca/scripts/toolkits/Gecko/structural_navigation.py 
b/src/orca/scripts/toolkits/Gecko/structural_navigation.py
index bc7b6ed..fc091e0 100644
--- a/src/orca/scripts/toolkits/Gecko/structural_navigation.py
+++ b/src/orca/scripts/toolkits/Gecko/structural_navigation.py
@@ -257,10 +257,8 @@ class GeckoStructuralNavigation(structural_navigation.StructuralNavigation):
         """
 
         isMatch = False
-        if self._script.utilities.isEntry(obj) \
-           or self._script.utilities.isPasswordText(obj):
-            state = obj.getState()
-            isMatch = state.contains(pyatspi.STATE_FOCUSABLE) \
+        state = obj.getState()
+        isMatch = state.contains(pyatspi.STATE_FOCUSABLE) \
                   and state.contains(pyatspi.STATE_SENSITIVE) \
                   and state.contains(pyatspi.STATE_EDITABLE)
 
diff --git a/test/html/aria-alert-dialog.html b/test/html/aria-alert-dialog.html
new file mode 100644
index 0000000..a814c2e
--- /dev/null
+++ b/test/html/aria-alert-dialog.html
@@ -0,0 +1,650 @@
+<html>
+<head>
+<style type="text/css">
+
+div.guess {
+  border: thick double black;
+  padding: 1em;
+  width: 50%;
+  font-family: Arial, Helvetica, sans-serif;
+}
+
+div.guess h2 {
+  margin: 0;
+  padding: 0;
+  text-align: center;
+  margin-left: 1em;
+  margin-right: 1em;
+}
+
+div.guess input {
+  font-size: 100%;
+}
+
+div.guess p.input {
+  margin: 0;
+  padding: 0;
+  font-size: 150%;
+  margin-top: .5em;
+  margin-bottom: .5em;
+  text-align: center;
+  margin-left: 1em;
+  margin-right: 1em;
+}
+
+div.guess input.button {
+  margin: 0;
+  padding: 0;
+  display: inline;
+  padding-left: .5em;
+  padding-right: .5em;
+  padding-top: .25em;
+  padding-bottom: .25em;
+}
+
+
+div#alert1 {
+  position: absolute;
+  width: 25%;
+  border:medium solid black;
+  display: none;
+  background-color: white;
+  color: black;
+  text-align: center;
+  padding-bottom: 1em;
+  font-family: Arial, Helvetica, sans-serif;
+}
+
+div#alert1 p.title {
+  margin: 0;
+  padding: 0;
+  color: white;
+  background-color: black;
+  text-align: center;
+  font-weight: bold;
+  border-top: thin solid white;
+  border-left: thin solid white;
+  border-right: thin solid white;
+}
+</style>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+<script type="text/javascript">
+$(document).ready(function () { 
+  var guess1 = new guess(1, 10, 'guess1', 'guess1_text', 'guess1_check', 'guess1_again', 'alert1'); 
+}); 
+
+// 
+// keyCodes is an object that defines keycodes for the key handlers 
+// 
+function keyCodes () { 
+  // Define values for keycodes 
+  this.tab        = 9; 
+  this.enter      = 13; 
+  this.esc        = 27; 
+  this.space      = 32; 
+} 
+
+// 
+// alertDlg() is a class to implement a modal alert dialog 
+// 
+// @param (alert_id string) alert_id is the id of the dialog to create 
+// 
+// @param (game_id string) game_id is the id to attach the dialog to 
+// @return N/A 
+// 
+function alertDlg(alert_id, game_id) { 
+  var dlg = '<div id="' + alert_id + '" role="alertdialog" tabindex="-1" aria-hidden="true" 
aria-labeledby="' + 
+    alert_id + '_title"><p id="' + alert_id + '_title" class="title">Alert Box</p><p id="' + 
+    alert_id + '_message">No Message</p><input id="' + 
+    alert_id + '_close" type="button" value="Close" /></div>'; 
+
+  // append the dialog to the document 
+  $('div#' + game_id).append(dlg); 
+
+  // Define the object properties 
+  this.$dlg  = $('#' + alert_id); // the object pointer of the dialog 
+  this.$game = $('#' + game_id); // the object pointer of the containing div for the game 
+  this.$msg = $('#' + alert_id + '_message'); // the object pointer of the alert message area 
+  this.$button = $('#' + alert_id + '_close'); // the object pointer of the alert close button 
+  this.$focus; // the object pointer of a page element to give focus to on dialog dismissal 
+
+  this.keys = new keyCodes(); 
+
+  // bind handlers 
+  this.bindHandlers(); 
+
+} // end alertDlg constructor 
+
+// 
+// showMsg() is a member function to set the message text of the alertDlg 
+// 
+// @param (msg string) msg is the message to display in the dialog box. 
+// 
+// @param (focusId string) focusId is the id of the element to give focus to when the dialog is dismissed. 
+// 
+// @return N/A 
+// 
+alertDlg.prototype.showMsg = function (msg, $focus) { 
+
+  // Store the focus ID 
+  this.$focus = $focus; 
+
+  // Set the message text 
+  this.$msg.html(msg); 
+
+  // Show the dialog 
+  this.showDlg(); 
+
+} // end showMsg() 
+
+// 
+// bindHandlers() is a member function to bind event handlers to the modal alert dialog 
+// 
+// @return N/A 
+// 
+alertDlg.prototype.bindHandlers = function () { 
+
+  var thisObj = this; // store the this pointer 
+
+  // bind a keydown handler 
+  this.$dlg.keydown(function(e) { 
+    return thisObj.handleDlgKeyDown(e); 
+  }); 
+
+  // bind a keypress handler 
+  this.$dlg.keypress(function(e) { 
+    return thisObj.handleDlgKeyPress(e); 
+  }); 
+
+  // bind a click handler 
+  this.$button.click(function(e) { 
+    return thisObj.handleCloseClick(e); 
+  }); 
+
+} // end bindhandlers() 
+
+// 
+// handleDlgKeyDown() is a member function to process keydown events for the alert dialog 
+// 
+// @param (evt obj) evt is the event object associated with the keydown event 
+// 
+// @return (boolean) true if propagating; false if consuming event 
+// 
+alertDlg.prototype.handleDlgKeyDown = function(evt) { 
+
+  if (evt.ctrlKey || evt.AltKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  switch (evt.keyCode) { 
+    case this.keys.tab: { 
+      // Consume the tab event and do nothing 
+      evt.stopPropagation; 
+      return false; 
+    } 
+    case this.keys.enter: 
+    case this.keys.esc: 
+    case this.keys.space: { 
+
+      // hide the dialog 
+      this.hideDlg(); 
+
+      evt.stopPropagation; 
+      return false; 
+
+      break; 
+    } 
+  } // end switch 
+
+  return true; 
+
+} // end handleDlgKeyDown() 
+
+// 
+// handleDlgKeyPress() is a member function to consume keypress events for the alert dialog 
+// 
+// @param (evt obj) evt is the event object associated with the keydown event 
+// 
+// @return (boolean) true if propagating; false if consuming event 
+// 
+alertDlg.prototype.handleDlgKeyPress = function(evt) { 
+
+  if (evt.ctrlKey || evt.AltKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  switch (evt.keyCode) { 
+    case this.keys.tab: 
+    case this.keys.enter: 
+    case this.keys.esc: 
+    case this.keys.space: { 
+
+      evt.stopPropagation; 
+      return false; 
+
+      break; 
+    } 
+  } // end switch 
+
+  return true; 
+
+} // end handleDlgKeyPress() 
+
+// 
+// handleCloseClick() is a member function to process click events for the alert dialog close button 
+// 
+// @param (evt obj) evt is the event object associated with the click event 
+// 
+// @return (boolean) true if propagating; false if consuming event 
+// 
+alertDlg.prototype.handleCloseClick = function(evt) { 
+
+  if (evt.shiftKey || evt.ctrlKey || evt.AltKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  // Hide the dialog 
+  this.hideDlg(); 
+
+  evt.stopPropagation; 
+  return false; 
+
+} // end handleCloseClick() 
+
+// 
+// showDlg() is a member function to show the alert dialog and give it focus 
+// 
+// @return N/A 
+// 
+alertDlg.prototype.showDlg = function() { 
+
+  var thisObj = this; 
+
+  // Bind an event listener to the document to capture all mouse events to make dialog modal 
+  $(document).bind('click mousedown mouseup mousemove mouseover', function(e) { 
+
+    //ensure focus remains on the dialog 
+    thisObj.$dlg.focus(); 
+
+    // Consume all mouse events and do nothing 
+    e.stopPropagation; 
+    return false; 
+  }); 
+
+  // Position the dialog centered in the containing div 
+  this.$dlg.css('left', (this.$game.width() - this.$dlg.width()) / 2 + this.$game.offset().left + 'px'); 
+  this.$dlg.css('top', (this.$game.height() - this.$dlg.height()) / 2 + this.$game.offset().top + 'px'); 
+
+  // Display the dialog 
+  this.$dlg.show(); 
+  this.$dlg.attr('aria-hidden', 'false'); 
+
+  // Give the dialog focus 
+  this.$dlg.attr('tabindex', '0'); 
+  this.$dlg.focus(); 
+
+} // end showDlg() 
+
+// 
+// hideDlg() is a member function to hide the alert dialog and return focus to the page 
+// 
+// @return N/A 
+// 
+alertDlg.prototype.hideDlg = function() { 
+
+  // set aria hidden attribute and remove dialog from tab order 
+  this.$dlg.attr('aria-hidden', 'true'); 
+  this.$dlg.attr('tabindex', '-1'); 
+
+  // hide the dialog 
+  this.$dlg.hide(); 
+
+  // Unbind the document mouse event listeners 
+  $(document).unbind('click mousedown mouseup mousemove'); 
+
+  // return focus to the specified page element 
+  if (this.$focus) { 
+    this.$focus.focus(); 
+  } 
+
+} // end hideDlg() 
+
+
+/////////////////////////////////////////////////////////////////////////////////////////// 
+// 
+// guess() is a class to implement a simple number guessing game 
+// 
+// @param (game_id) game_id is the id to attach the instance of the game to. 
+// 
+// @param (max integer) min is the maximum number to guess. 
+// 
+// @param (text_id string) text_id is the id of the text box where player enters a guess. 
+// 
+// @param (check_id string) check_id is the id of the check guess button. 
+// 
+// @param (again_id string) again_id is the id of the play again button. 
+// 
+// @param (alertObj) alertObj is the modal dialog object where game messages will be printed. 
+// 
+// @return N/A 
+// 
+function guess(min, max, game_id, text_id, check_id, again_id, alert_id) { 
+   
+  // define class properties 
+  this.minGuess = min;         // the minimum number to guess 
+  this.maxGuess = max;         // the maximum number to guess 
+  this.$text = $('#' + text_id);   // the jQuery object pointer to the text box 
+  this.$check = $('#' + check_id); // the jQuery object pointer to the check guess button 
+  this.$again = $('#' + again_id); // the jQuery object pointer to the play again button 
+  this.alertDlg = new alertDlg('alert1', game_id); // the modal alert dialog to be displayed during the game 
+
+  this.guessVal = -1;        // the number for the player to guess 
+  this.guessCount = 0;       // the number of attempts the player has made 
+
+  this.keys = new keyCodes(); 
+
+  // bind event handlers 
+  this.bindHandlers(); 
+
+  // initialize the game 
+  this.newGame(); 
+
+} // end guess object constructor 
+
+// 
+// newGame() is a member function to set up a new game. The function chooses a number 
+// between 1 and the max number specified at instantiation, sets the guess count to 0, and 
+// show the user a message to make a guess. 
+// 
+// @return N/A 
+guess.prototype.newGame = function () { 
+
+  // get a new random number for the player to guess 
+  this.guessVal = Math.floor(Math.random()*(this.maxGuess - this.minGuess + 1)) + this.minGuess; 
+   
+  // reset the guess count 
+  this.guessCount = 0; 
+
+  // reset the guess text box 
+  this.$text.val(''); 
+  this.$text.attr('aria-invalid', 'false'); 
+
+  // Re-enable the buttons 
+  this.$text.removeAttr('disabled'); 
+  this.$check.removeAttr('disabled'); 
+
+  // Set focus on the guess text box 
+  this.$text.focus(); 
+
+} // end newGame 
+
+// 
+// bindHandlers() is a function to bind the event handlers for the game controls 
+// 
+// @return N/A 
+// 
+guess.prototype.bindHandlers = function () { 
+
+  var thisObj = this; // Store the this pointer 
+
+  // bind a focus handler for the guess text box 
+  this.$text.focus(function (e) { 
+    thisObj.handleTextFocus(e); 
+    return true; 
+  }); 
+
+  // bind a keydown handler for the guess text box 
+  this.$text.keydown(function (e) { 
+    return thisObj.handleTextKeyDown(e); 
+  }); 
+
+  // bind a keypress handler for the guess text box 
+  this.$text.keypress(function (e) { 
+    return thisObj.handleTextKeyPress(e); 
+  }); 
+
+  // bind a click handler for the check guess button 
+  this.$check.click(function (e) { 
+    return thisObj.handleCheckClick(e); 
+  }); 
+
+  // bind a click handler for the play again button 
+  this.$again.click(function (e) { 
+    return thisObj.handleAgainClick(e); 
+  }); 
+
+} // end bindHandlers() 
+
+// 
+// handleTextFocus() is a member function to process focus events for the guess text box 
+// 
+// @input (evt obj) evt is the event object associated with the keydown event 
+// 
+// @return N/A 
+// 
+guess.prototype.handleTextFocus = function(evt) { 
+
+  // Select any text in the text box 
+  this.$text.select(); 
+
+} // end handleTextFocus() 
+
+// 
+// handleTextKeyDown() is a member function to process keydown events for the guess text box 
+// 
+// @input (evt obj) evt is the event object associated with the keydown event 
+// 
+// @return (boolean) false if consuming event, true if propagating 
+// 
+guess.prototype.handleTextKeyDown = function(evt) { 
+
+  // do nothing if shift, alt, or ctrl key pressed. 
+  if (evt.shiftKey || evt.altKey || evt.ctrlKey) { 
+    return true; 
+  } 
+
+  if (evt.keyCode == this.keys.enter) { 
+
+    // validate the guess 
+    if (this.validateGuess() == true) { 
+
+      // increment the guess count 
+      this.guessCount++; 
+
+      // see if the player has won 
+      if (this.checkGuess() == true) { 
+        // disable the guess text box and the check guess button 
+        this.$text.attr('disabled', 'true'); 
+        this.$check.attr('disabled', 'true'); 
+      } 
+    } 
+
+    evt.stopPropagation; 
+    return false; 
+  } 
+
+  return true; 
+
+} // end handleTextKeyDown() 
+
+// 
+// handleTextKeyPress() is a member function to process keypress events for the guess text box. This 
function 
+// is included to handle browsers that perform window scrolling, etc. on keypress rather than keydown. 
+// 
+// @input (evt obj) evt is the event object associated with the keypress event 
+// 
+// @return (boolean) false if consuming event, true if propagating 
+// 
+guess.prototype.handleTextKeyPress = function(evt) { 
+
+  // do nothing if shift, alt, or ctrl key pressed. 
+  if (evt.shiftKey || evt.altKey || evt.ctrlKey) { 
+    return true; 
+  } 
+
+  if (evt.keyCode == this.enterKey) { 
+
+    // consume the event 
+    evt.stopPropagation; 
+    return false; 
+  } 
+
+  return true; 
+
+} // end handleTextKeyPress() 
+
+// 
+// handleCheckClick() is a member function to process click events for the check guess button 
+// 
+// @input (evt obj) evt is the event object associated with the click event 
+// 
+// @return (boolean) false if consuming event, true if propagating 
+// 
+guess.prototype.handleCheckClick = function(evt) { 
+
+  // do nothing if shift, alt, or ctrl key pressed. 
+  if (evt.shiftKey || evt.altKey || evt.ctrlKey) { 
+    return true; 
+  } 
+
+  // validate the guess 
+  if (this.validateGuess() == true) { 
+
+    // increment the guess count 
+    this.guessCount++; 
+
+    // see if the player has won 
+    if (this.checkGuess() == true) { 
+      // disable the guess text box and the check guess button 
+      this.$text.attr('disabled', 'true'); 
+      this.$check.attr('disabled', 'true'); 
+    } 
+  } 
+     
+  evt.stopPropagation; 
+  return false; 
+
+} // end handleCheckClick() 
+
+// 
+// handleAgainClick() is a member function to process click events for the play again button 
+// 
+// @input (evt obj) evt is the event object associated with the click event 
+// 
+// @return (boolean) false if consuming event, true if propagating 
+// 
+guess.prototype.handleAgainClick = function(evt) { 
+
+  // do nothing if shift, alt, or ctrl key pressed. 
+  if (evt.shiftKey || evt.altKey || evt.ctrlKey) { 
+    return true; 
+  } 
+
+  // Setup a new game 
+  this.newGame(); 
+
+  evt.stopPropagation; 
+  return false; 
+
+} // end handleTextKeyDown() 
+
+// 
+// validateGuess() is a member function to validate a player's guess. If the guess is not a number, is less 
than 
+// the minimum allowed guess, or is greater than the maximum allowed guess, the user is warned that the 
guess is invalid 
+// 
+// @return (boolean) true if guess is valid; false if guess is invalid 
+// 
+guess.prototype.validateGuess = function() { 
+  var val = this.$text.val(); 
+
+  if (this.$text.val() == '') { 
+    // guess is empty 
+    this.$text.attr('aria-invalid', 'true'); 
+    this.alertDlg.showMsg('You must enter a number!', this.$text); 
+
+    return false; 
+  } 
+  else if (isNaN(val) == true) { 
+
+    // guess is not a number 
+    this.$text.attr('aria-invalid', 'true'); 
+    this.alertDlg.showMsg('\'' + this.$text.val() + '\' is not a number!', this.$text); 
+
+    return false; 
+  } 
+  else if (val < this.minGuess || val > this.maxGuess) { 
+
+    // guess is out of range 
+    this.$text.attr('aria-invalid', 'true'); 
+    this.alertDlg.showMsg('You must choose a number between ' + this.minGuess + ' and ' + this.maxGuess + 
'!', this.$text); 
+
+    return false; 
+  } 
+   
+  this.$text.attr('aria-invalid', 'false'); 
+
+  return true; 
+
+} // end validateGuess() 
+
+// 
+// checkGuess() is a member function to check the player's guess to see if he or she has won the game 
+// 
+// @return (boolean) true if the player has won; false if not 
+guess.prototype.checkGuess = function() { 
+
+  var guess = this.$text.val(); 
+
+  if (guess == this.guessVal) { 
+
+    // The player has won. Tell the player how many tries it took 
+
+    if (this.guessCount == 1) { 
+      this.alertDlg.showMsg('\'' + guess + '\' is right. You got it on your first try!', this.$again); 
+    } 
+    else { 
+      this.alertDlg.showMsg('\'' + guess + '\' is right. It only took you ' + this.guessCount + ' tries!', 
this.$again); 
+    } 
+    return true; 
+  } 
+
+  // Player did not guess the correct number. Tell the player if he or she is too high or too low 
+  if (guess < this.guessVal) { 
+    this.alertDlg.showMsg('\'' + guess + '\' is too low. Try a higher number.', this.$text); 
+  } 
+  else { 
+    this.alertDlg.showMsg('\'' + guess + '\' is too high. Try a lower number.', this.$text); 
+  } 
+
+  return false; 
+
+} // end checkGuess() 
+  </script>
+</head>
+<body>
+<div role="application"> 
+
+<div id="guess1" class="guess"> 
+
+  <h2>Number Guessing Game</h2> 
+   
+  <p><strong>Instructions:</strong> In this game you guess a number between 1 an 10 and then press the 
"Check My Guess" button to check your responses.   
+    An <abbr title="Accessible Rich Internet Application">ARIA</abbr> dialog box will display the results of 
your guess.  To start over again to press the "Play Again" button.</p> 
+
+  <p class="input"> 
+    <label id="guess1_label" for="guess1_text">Guess a number between 1 and 10</label> 
+    <input type="text" id="guess1_text" size="3" aria-labelledby="guess1_label" aria-invalid="false"> 
+  </p> 
+
+  <p class="input">     
+    <input class="button" id="guess1_check" type="button" value="Check My Guess"/> 
+    <input class="button" id="guess1_again" type="button" value="Play Again"/> 
+  </p> 
+</div> 
+
+</div>
+</body>
+</html>
diff --git a/test/html/aria-button-toggle.html b/test/html/aria-button-toggle.html
new file mode 100644
index 0000000..39c73dd
--- /dev/null
+++ b/test/html/aria-button-toggle.html
@@ -0,0 +1,400 @@
+<!DOCTYPE HTML>
+<html lang="en-us">
+<head>
+<style type="text/css">
+
+ul.buttons {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+}
+
+ul.buttons li {
+  float: left;
+  text-align: center;
+  margin-right: .25em;
+  padding-left: .25em;
+  padding-right: .25em;
+  width: 1em;
+  font-weight: bold;
+  height: 100%;
+  border: 2px solid black;
+}
+
+ul.buttons li[aria-pressed="true"] {
+  border-top: black 3px solid;
+  border-left: black 3px solid;
+  border-bottom: black 1px solid;
+  border-right:  black 1px solid;
+  
+}
+
+ul.buttons li[aria-pressed="false"] {
+  border-top: black 1px solid;
+  border-left: black 1px solid;
+  border-bottom: black 3px solid;
+  border-right: black 3px solid;
+  
+}
+
+ul.buttons li[aria-pressed="true"]:focus,
+ul.buttons li[aria-pressed="true"]:active{
+  border-top: #CCCCCC 3px solid;
+  border-left: #CCCCCC 3px solid;
+  border-bottom: #CCCCCC 1px solid;
+  border-right:  #CCCCCC 1px solid;
+  color: white;
+  background-color: black;
+  
+}
+
+ul.buttons li[aria-pressed="false"]:focus,
+ul.buttons li[aria-pressed="false"]:active{
+  border-top: #CCCCCC 1px solid;
+  border-left: #CCCCCC 1px solid;
+  border-bottom: #CCCCCC 3px solid;
+  border-right: #CCCCCC 3px solid;
+  color: white;
+  background-color: black;
+  
+}
+
+.italic {
+  font-style: italic;
+} 
+
+.bold {
+  font-weight: bold;
+}
+
+ul.buttons{
+  font-weight: bold;
+}
+
+textarea.example {
+  clear: both;
+  padding: .25em;
+  width: 50%;
+  height: 200px;
+}
+
+.hide {
+position: absolute;
+top: -20em;
+left: -200em;
+} 
+</style>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+</head> 
+<body>
+<div role="application">
+<h3>Text Sample 1</h3>
+<ul class="buttons" title="Text Formating Controls 1">
+    <li id="larger1"  
+        role="button"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text1"
+        aria-labelledby="larger_label">+</li>           
+    <li id="smaller1"  
+        role="button"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text1"
+        aria-labelledby="smaller_label">-</li>
+    <li id="italic1"  
+        role="button"
+        class="toggleButton italic"
+        tabindex="0"
+        aria-pressed="true"
+        aria-controls="text1"
+        aria-labelledby="italic_label">i</li>
+    <li id="bold1"  
+        role="button"
+        class="toggleButton"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text1"
+        aria-labelledby="bold_label">B</li>
+</ul>
+
+<p style="clear: both; height: 1px">&nbsp;</p>
+
+<textarea id="text1" name="text1" class="example italic"> 
+Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in 
Liberty, and dedicated to the proposition that all men are created equal.
+
+Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so 
dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a 
portion of that field, as a final resting place for those who here gave their lives that that nation might 
live. It is altogether fitting and proper that we should do this.
+</textarea>        
+<p>&nbsp;</p>
+
+<h3>Text Sample 2</h3>
+
+<ul class="buttons" title="Text Formating Controls 2">
+
+    <li id="larger2"  
+        role="button"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text2"
+        aria-labelledby="larger_label">+</li>
+            
+    <li id="smaller2"  
+        role="button"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text2"
+        aria-labelledby="smaller_label">-</li>
+           
+    <li id="italic2"  
+        role="button"
+        class="toggleButton italic"
+        tabindex="0"
+        aria-pressed="false"
+        aria-controls="text2"
+        aria-labelledby="italic_label">i</li>
+        
+    <li id="bold2"  
+        role="button"
+        class="toggleButton"
+        tabindex="0"
+        aria-pressed="true"
+        aria-controls="text2"
+        aria-labelledby="bold_label">B</li>
+        
+</ul>
+
+<p style="clear: both; height: 1px">&nbsp;</p>
+
+<textarea id="text2" name="text2" class="example bold">
+But, in a larger sense, we can not dedicate - we can not consecrate - we can not hallow - this ground. The 
brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or 
detract. The world will little note, nor long remember what we say here, but it can never forget what they 
did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought 
here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining 
before us - that from these honored dead we take increased devotion to that cause for which they gave the 
last full measure of devotion - that we here highly resolve that these dead shall not have died in vain - 
that this nation, under God, shall have a new birth of freedom - and that government of the people, by the 
people, for the people, shall not perish from the earth. 
+</textarea>
+
+<p class="hide" id="bold_label">Bold</p>
+
+<p class="hide" id="italic_label">Italic</p>
+
+<p class="hide" id="larger_label">Font Larger</p>
+
+<p class="hide" id="smaller_label">Font Smaller</p>
+
+</div>
+<script type="text/javascript">
+var KEY_ENTER = 13;
+var KEY_SPACE = 32;
+
+$(document).ready(function() {
+
+       $('ul.buttons li').mousedown(function(event) {
+
+               var ariaControls = '#' + $(this).attr('aria-controls');
+
+               switch($(this).attr('aria-labelledby')) {
+                       case 'italic_label': {
+                               $(ariaControls).toggleClass('italic');
+                               break;
+                       }
+                       case 'bold_label': {
+                               $(ariaControls).toggleClass('bold');
+                               break;
+                       }
+                       case 'larger_label': {
+                               increaseFontSize(ariaControls);
+                               break;
+                       }
+                       case 'smaller_label': {
+                               decreaseFontSize(ariaControls);
+                               break;
+                       }
+               } // end switch
+
+               if ($(this).hasClass('toggleButton') == true) {
+
+                               // This is a toggle button: toggle aria-pressed state
+                               togglePressed(this);
+               }
+               else
+               {
+                               // This is a momentary pushbutton: Set aria-pressed to true
+                               $(this).attr('aria-pressed', 'true');
+               }
+
+               $(this).focus();
+
+               event.stopPropagation();
+               return false;
+       }); // end button click handler
+
+       // bind a mouseup handler to the buttons to enable momentary pushbuttons
+       // to return to unpressed state and toggle buttons to remain pressed
+       // 
+       $('ul.buttons li').mouseup(function(event) {
+
+               if ($(this).hasClass('toggleButton') == false) {
+
+                       // Set aria-pressed to false
+                       $(this).attr('aria-pressed', 'false');
+               }
+
+               event.stopPropagation();
+               return false;
+       }); // end mouseup handler
+
+       // keypress handler
+       //
+       // The Opera browser detects keystrokes to perform window manipulation during the keypress event,
+       // not keydown like IE, Firefox, and Safari. Relevant keypresses are consumed by this handler to
+       // make the browser behave properly when the user is manipulating the buttons.
+       //
+       $('ul.buttons li').keypress(function(event) {
+
+               switch (event.which) {
+                       case KEY_ENTER:
+                       case KEY_SPACE: {
+                               event.stopPropagation;
+                               return false;
+                               break;
+                       }
+               } //end switch
+               return true;
+       });
+
+       $('ul.buttons li').keydown(function(event) {
+
+               var ariaControls = '#' + $(this).attr('aria-controls');
+
+               switch (event.which) {
+                       case KEY_ENTER:
+                       case KEY_SPACE: {
+                               switch($(this).attr('aria-labelledby')) {
+                                       case 'italic_label': {
+                                               $(ariaControls).toggleClass('italic');
+                                               break;
+                                       }
+                                       case 'bold_label': {
+                                               $(ariaControls).toggleClass('bold');
+                                               break;
+                                       }
+                                       case 'larger_label': {
+                                               increaseFontSize(ariaControls);
+                                               break;
+                                       }
+                                       case 'smaller_label': {
+                                               decreaseFontSize(ariaControls);
+                                               break;
+                                       }
+                               } // end switch
+
+                               if ($(this).hasClass('toggleButton') == true) {
+
+                                               // This is a toggle button: toggle aria-pressed state
+                                               togglePressed(this);
+                               }
+                               else
+                               {
+                                               // This is a momentary pushbutton: Set aria-pressed to true
+                                               $(this).attr('aria-pressed', 'true');
+                               }
+
+                               event.stopPropagation();
+                               return false;
+
+                       } // end case
+               } // end switch
+
+               return true;
+       }); // end button click handler
+
+       // bind a keyup handler to the buttons to enable momentary pushbuttons
+       // to return to unpressed state and toggle buttons to remain pressed
+       // 
+       $('ul.buttons li').keyup(function(event) {
+               
+               id = this;
+
+               switch (event.which) {
+                       case KEY_ENTER:
+                       case KEY_SPACE: {
+                               if ($(this).hasClass('toggleButton') == false) {
+                               
+                                       // set aria-pressed to false
+                                       $(id).attr('aria-pressed', 'false');
+                               }
+
+                               event.stopPropagation();
+                               return false;
+                       } // end case
+               } // end switch
+
+               return true;
+       }); // end mouseup handler
+
+       /**
+        * increaseFontSize() increases the font size for the controlled area
+        *
+        * @param (ariaControls) id of text area to modify
+        *
+        * @return N/A
+        */
+       function increaseFontSize(ariaControls) {
+       
+               var $text = $(ariaControls);
+               var fontSize = parseFloat($text.css('fontSize'), 10);
+       
+               // increase the font size
+               fontSize *= 1.4;
+       
+               if (fontSize > 120) {
+                       return;
+               }
+               // write the new value to the css property
+               // note: 'px' must be appended for valid css
+               $text.css('fontSize', fontSize+'px');
+       } // end increaseFontSize()
+       
+       /**
+        * decreaseFontSize() decreases the font size for the controlled area
+        *
+        * @param (ariaControls) id of text area to modify
+        *
+        * @return N/A
+        */
+       function decreaseFontSize(ariaControls) {
+       
+               var $text = $(ariaControls);
+               var fontSize = parseFloat($text.css('fontSize'), 10);
+       
+               // increase the font size
+               fontSize /= 1.4;
+       
+               if (fontSize < 4) {
+                       return;
+               }
+       
+               // write the new value to the css property
+               // note: 'px' must be appended for valid css
+               $text.css('fontSize', fontSize+'px');
+       
+       } // end decreaseFontSize
+       
+       /**
+        * togglePressed() toggles the aria-pressed atribute between true or false
+        *
+        * @param ( id object) button to be operated on
+        *
+        * @return N/A
+        */
+       function togglePressed(id) {
+       
+               // reverse the aria-pressed state
+               if ($(id).attr('aria-pressed') == 'true') {
+                       $(id).attr('aria-pressed', 'false');
+               }
+               else {
+                       $(id).attr('aria-pressed', 'true');
+               }
+       }
+
+}); // end ready
+</script>
+</body>
+</html>
diff --git a/test/html/aria-radiobutton.html b/test/html/aria-radiobutton.html
new file mode 100644
index 0000000..caaa5ab
--- /dev/null
+++ b/test/html/aria-radiobutton.html
@@ -0,0 +1,407 @@
+<html>
+<head>
+<style type="text/css">
+ul.radiogroup {
+    margin: 0;
+    padding: 0;                
+}
+
+ul.radiogroup  li   {
+    padding: 0; 
+    margin: 0;
+    margin-left: 1em;
+    padding: 4px;
+    list-style: none;
+    width: 6em;          
+}
+    
+ul.radiogroup li:hover {
+    padding: 2px;
+    border: gray 2px solid;
+}
+
+ul.radiogroup li.selected {
+    padding: 2px;
+    border: black 2px solid;
+   }
+
+.offscreen {
+  position: absolute;
+         left: -200em;
+         top: -20em;
+}
+</style>
+</head> 
+<body>
+
+<div role="application">
+
+  <h3 id="rg1_label">Lunch Options</h3>
+ 
+  <ul class="radiogroup" id="rg1" role="radiogroup" aria-labelledby="rg1_label">
+    <li id="r1" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Thai
+    </li>
+    <li id="r2" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Subway
+    </li>
+    <li id="r3" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Jimmy Johns
+    </li>
+    <li id="r4" tabindex="0" role="radio" aria-checked="true">
+      <img role="presentation" src="radio-checked.gif" alt="">
+      Radio Maria
+    </li>
+    <li id="r5" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Rainbow Gardens
+    </li>       
+  </ul>        
+  <h3 id="rg2_label">Drink Options</h3>
+   
+  <ul id="rg2" class="radiogroup" role="radiogroup" aria-labelledby="rg2_label">
+    <li id="r6" tabindex="0" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Water
+    </li>
+    <li id="r7" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Tea
+    </li>
+    <li id="r8" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Coffee
+    </li>
+    <li id="r9" tabindex="-1" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Cola
+    </li>
+    <li id="r10" tabindex="0" role="radio" aria-checked="false">
+      <img role="presentation" src="radio-unchecked.gif" alt="">
+      Ginger Ale
+    </li>       
+  </ul>        
+ 
+</div>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+<script type="text/javascript">
+$(document).ready(function() {
+
+       var group1 = new radioGroup('rg1');
+       var group2 = new radioGroup('rg2');
+
+}); // end ready
+
+function keyCodes () {
+  // Define values for keycodes
+  this.enter      = 13;
+  this.space      = 32;
+
+  this.left       = 37;
+  this.up         = 38;
+  this.right      = 39;
+  this.down       = 40;
+} 
+
+//
+// Function radioGroup() is a class to define an ARIA-enabled radiogroup widget.
+//
+// This widget attaches to an unordered list and makes each list entry a group
+// of radio buttons.
+//
+// @param (id object) id is the html id of the <ul> to attach to
+//
+// @return N/A
+//
+function radioGroup(id) {
+
+       var thisObj = this;
+
+       ///////// define widget properties ///////////////
+
+       this.$id = $('#' + id);
+
+       // find all list items with a role of radio
+       this.$buttons = this.$id.find('li').filter('[role=radio]');
+
+       // Store the currently checked item
+       this.$checked = this.$buttons.filter('[aria-checked=true]');
+
+       this.checkButton = true; // set to false during ctrl+arrow operations;
+
+       this.$active = null; // the selected button (may not be checked)
+       
+       this.keys = new keyCodes();
+
+       ///////////// Bind Event handlers ////////////////
+
+       this.$buttons.click(function(e) {
+               return thisObj.handleClick(e, $(this));
+       });
+
+       this.$buttons.keydown(function(e) {
+               return thisObj.handleKeyDown(e, $(this));
+       });
+
+       this.$buttons.keypress(function(e) {
+               return thisObj.handleKeyPress(e, $(this));
+       });
+
+       this.$buttons.focus(function(e) {
+               return thisObj.handleFocus(e, $(this));
+       });
+
+       this.$buttons.blur(function(e) {
+               return thisObj.handleBlur(e, $(this));
+       });
+}
+
+// 
+// Function selectButton() is a member function to select and possibly check a button in the
+// radioGroup.
+//
+// @param ($id object) $id is the jQuery object of the button to select
+//
+// @return N/A
+//
+radioGroup.prototype.selectButton = function($id) {
+
+       if (this.checkButton == true) {
+               // checking the button
+
+               // remove the checked image from the previously checked button
+               this.$checked.find('img').attr('src', 'radio-unchecked.gif');
+
+               // update the button image
+               $id.find('img').attr('src', 'radio-checked.gif');
+
+               if (this.$checked.length == 0) { // no previously checked group buttons
+                       // the first and last items in the group will have
+                       // tabindex=0. Remove them both from the tab order.
+                       this.$buttons.first().attr('tabindex', '-1');
+
+                       this.$buttons.last().attr('tabindex', '-1');
+               }
+               else {
+                       // remove the previously checked item from
+                       // the tab order and modify it's aria attributes accordingly
+                       this.$checked.attr('tabindex', '-1').attr('aria-checked', 'false');
+               }
+
+               // Place this button in the tab order and modify it's aria attributes
+               $id.attr('tabindex', '0').attr('aria-checked', 'true');
+
+               // update the stored $checked object
+               this.$checked = $id;
+       }
+
+       // update the stored $active object
+       this.$active = $id;
+
+       // give this button the selected class
+       $id.addClass('selected');
+
+       // Reset checkButton flag - in case it was false
+       this.checkButton = true;
+
+} // end selectButton()
+
+//
+// Function handleClick() is a member function to process keydown events for the radioGroup.
+//
+// @param (e object) e is the event object
+//
+// @param ($id object) $is is the jquery object of the triggering element
+//
+// @return (boolean) Returns false if consuming event; true if propagating
+//
+radioGroup.prototype.handleClick = function(e, $id) {
+
+       if (e.altKey || e.ctrlKey || e.shiftKey) {
+               // do nothing
+               return true;
+       }
+
+       // simply consume the event - browser calls focus()
+
+       e.stopPropagation();
+       return false;
+
+} // end handleClick()
+
+//
+// Function handleKeyDown() is a member function to process keydown events for the radioGroup.
+//
+// @param (e object) e is the event object
+//
+// @param ($id object) $is is the jquery object of the triggering element
+//
+// @return (boolean) Returns false if consuming event; true if propagating
+//
+radioGroup.prototype.handleKeyDown = function(e, $id) {
+
+       if (e.altKey) {
+               // do nothing
+               return true;
+       }
+
+       switch (e.keyCode) {
+               case this.keys.space:
+               case this.keys.enter: {
+                       if (e.ctrlkey || e.shiftKey) {
+                               // do nothing
+                               return true;
+                       }
+
+                       // select and check the button
+                       this.selectButton($id);
+
+                       e.stopPropagation();
+                       return false;
+               }
+               case this.keys.left:
+               case this.keys.up: {
+
+                       var $prev = $id.prev(); // the previous button
+
+                       if (e.shiftKey) {
+                               // do nothing
+                               return true;
+                       }
+
+                       // if this was the first item
+                       // select the last one in the group.
+                       if ($id.index() == 0) {
+                               $prev = this.$buttons.last();
+                       }
+
+                       if (e.ctrlKey) {
+                               // set checkButton to false so
+                               // focus does not check button
+                               this.checkButton = false;
+                       }
+
+                       // select the previous button
+                       $prev[0].focus();
+
+                       e.preventDefault();
+                       e.stopPropagation();
+                       return false;
+               }
+               case this.keys.right:
+               case this.keys.down: {
+
+                       var $next = $id.next(); // the next button
+
+                       if (e.shiftKey) {
+                               // do nothing
+                               return true;
+                       }
+
+                       // if this was the last item,
+                       // select the first one in the group.
+                       if ($id.index() == this.$buttons.length - 1) {
+                               $next = this.$buttons.first();
+                       }
+
+                       if (e.ctrlKey) {
+                               // set checkButton to false so
+                               // focus does not check button
+                               this.checkButton = false;
+                       }
+
+                       // select the next button
+                       $next[0].focus();
+
+                       e.preventDefault();
+                       e.stopPropagation();
+                       return false;
+               }
+       } // end switch
+
+       return true;
+
+} // end handleKeyDown()
+
+//
+// Function handleKeyPress() is a member function to process keydown events for the radioGroup.
+// This is needed to prevent browsers that process window events on keypress (such as Opera) from
+// performing unwanted scrolling of the window, etc.
+//
+// @param (e object) e is the event object
+//
+// @param ($id object) $is is the jquery object of the triggering element
+//
+// @return (boolean) Returns false if consuming event; true if propagating
+//
+radioGroup.prototype.handleKeyPress = function(e, $id) {
+
+       if (e.altKey) {
+               // do nothing
+               return true;
+       }
+
+       switch (e.keyCode) {
+               case this.keys.space:
+               case this.keys.enter: {
+                       if (e.ctrlKey || e.shiftKey) {
+                               // do nothing
+                               return true;
+                       }
+               }
+               case this.keys.left:
+               case this.keys.up:
+               case this.keys.right:
+               case this.keys.down: {
+                       if (e.shiftKey) {
+                               // do nothing
+                               return true;
+                       }
+                       e.stopPropagation();
+                       return false;
+               }
+       } // end switch
+
+       return true;
+
+} // end handleKeyPress()
+
+//
+// Function handleFocus() is a member function to process focus events for the radioGroup.
+//
+// @param (e object) e is the event object
+//
+// @param ($id object) $is is the jquery object of the triggering element
+//
+// @return (boolean) Returns false if consuming event; true if propagating
+//
+radioGroup.prototype.handleFocus = function(e, $id) {
+
+       // select the button
+       this.selectButton($id);
+
+       return true;
+} // end handleFocus()
+
+//
+// Function handleBlur() is a member function to process blur events for the radioGroup.
+//
+// @param (e object) e is the event object
+//
+// @param ($id object) $is is the jquery object of the triggering element
+//
+// @return (boolean) Returns false if consuming event; true if propagating
+//
+radioGroup.prototype.handleBlur = function(e, $id) {
+
+       // remove the focus styling from this buttons
+       $id.removeClass('selected');
+
+       return true;
+} // end handleBlur()
+  </script>
+</body>
+</html>
diff --git a/test/html/aria-sliders.html b/test/html/aria-sliders.html
new file mode 100644
index 0000000..3564f7a
--- /dev/null
+++ b/test/html/aria-sliders.html
@@ -0,0 +1,869 @@
+<html>
+<head>
+<style type="text/css">
+.label { 
+  margin: 0; 
+  padding: 0; 
+  margin-top: 2em; 
+  margin-bottom: .5em;   
+  clear: both; 
+  font-weight: bold; 
+} 
+
+div.hslider { 
+  margin: 50px; 
+  padding: 0; 
+  width: 540px; 
+  height: 20px; 
+  background-color: #eef; 
+  border: 2px solid black; 
+} 
+
+.hsliderHandle  { 
+  margin: 0; 
+  padding: 7px 2px; 
+  width: 24px; 
+  height: 12px; 
+  background-color: #808080; 
+
+  position: absolute; 
+  left: -300em; 
+  top: -30em; 
+  z-index: 10; 
+
+  border: 1px solid black; 
+  -webkit-border-radius: 5px; /* Safari and Chrome rounded corners */ 
+  -moz-border-radius: 5px; /* Firefox rounded corners */ 
+  border-radius: 5px; /* Opera rounded corners */ 
+
+} 
+
+.hsliderValue  { 
+  margin: 24px 0 0 0; 
+  padding: 5px; 
+  width: 30px; 
+  height: 15px; 
+  text-align: center; 
+  font-weight: bold; 
+
+  position: absolute; 
+  left: -30em; 
+  top: -30em; 
+  z-index: 10; 
+} 
+
+div.vslider { 
+  margin: 50px; 
+  padding: 0; 
+  height: 540px; 
+  width: 20px; 
+  background-color: #eef; 
+  border: 2px solid black; 
+} 
+
+.vsliderHandle  { 
+  margin: 0; 
+  padding: 2px 7px; 
+  width: 12px; 
+  height: 24px; 
+  background-color: #808080; 
+
+  position: absolute; 
+  left: -300em; 
+  top: -30em; 
+  z-index: 10; 
+
+  border: 1px solid black; 
+  -webkit-border-radius: 5px; /* Safari and Chrome rounded corners */ 
+  -moz-border-radius: 5px; /* Firefox rounded corners */ 
+  border-radius: 5px; /* Opera rounded corners */ 
+} 
+
+.vsliderValue  { 
+  margin: 0 0 0 30px; 
+  padding: 5px; 
+  width: 30px; 
+  height: 15px; 
+  text-align: center; 
+  font-weight: bold; 
+
+  position: absolute; 
+  left: -30em; 
+  top: -30em; 
+  z-index: 10; 
+} 
+
+div.sliderRange { 
+  margin: 2px; 
+  padding: 0; 
+  width: 1px; 
+  height: 1px; 
+  background-color: #00f; 
+
+  position: absolute; 
+  left: -300em; 
+  top: -30em; 
+  z-index: 0; 
+} 
+
+.hidden { 
+  position: absolute; 
+  top: -20em; 
+  left: -200em; 
+} 
+
+.focus { 
+  background-color: #eee !important; 
+} 
+</style>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+<script type="text/javascript">
+$(document).ready(function() {
+
+  // slider1 is a horizontal slider
+  var slider1 = new slider('sr1', false, 0, 100, 5, 10, true, false, 30); 
+
+  // slider2 is a horizontal range slider
+  var slider2 = new slider('sr2', false, 1900, 2008, 1, 10, true, true, 1950, 2000);
+
+  // slider3 is a vertical range slider
+  //var slider3 = new slider('sr3', true, 0, 100, 1, true, false, 25);
+  var slider3 = new slider('sr3', true, 1900, 2008, 1, 10, true, true, 1950, 2000);
+}); // end document ready
+
+
+//
+// function keyCodes() is an object to contain key code values for the application
+//
+function keyCodes() {
+  // Define values for keycodes
+  this.backspace  = 8;
+  this.tab        = 9;
+  this.enter      = 13;
+  this.esc        = 27;
+
+  this.space      = 32;
+  this.pageup     = 33;
+  this.pagedown   = 34;
+  this.end        = 35;
+  this.home       = 36;
+
+  this.left       = 37;
+  this.up         = 38;
+  this.right      = 39;
+  this.down       = 40; 
+
+} // end keyCodes
+
+////////////////////////////////////////////////////
+//
+// function slider() is a class to define an ARIA-enabled slider widget. The class
+// will create needed handles and define ARIA attributes for the slider
+//
+// @param(container_id string) container_id is the containing div for the slider
+//
+// @param(vert boolean) vert is true if the slider is vertical; false if horizontal
+//
+// @param(inc integer) inc is the increment value for the slider
+//
+// @param(jump integer) jump is the large increment value for the slider (pgUp/pgDown keys)
+//
+// @param(showVals boolean) showVals is true if the slider should display the value of the handles
+//
+// @param(range boolean) range is true if the slider is a range slider
+//
+// @param(val1 integer) val1 specifies the initial value of the slider or of the first
+//         slide handle if this is a range slider. Must be >= min.
+//
+// @param(val2 integer) val2 specifies the initial value of the second slide handle.
+//         Ignored if range is false (i.e. not a range slider). Must be <= max.
+//
+// @return N/A
+//
+function slider(container_id, vert, min, max, inc, jump, showVals, range, val1, val2) {
+
+  // define slider object properties
+  this.keys = new keyCodes();
+
+  this.id = container_id;
+  this.$container = $('#' + container_id);
+  this.vert = vert;
+  this.range = range;
+  this.showVals = showVals;
+
+  // Store the size of the slider
+  this.width = this.$container.outerWidth();
+  this.height = this.$container.outerHeight();
+
+  // Store the page position of the slider
+  this.left = Math.round(this.$container.offset().left);
+  this.top = Math.round(this.$container.offset().top);
+
+  // Store the minimum and maximum and initial values
+  this.min = min;
+  this.max = max;
+  this.inc = inc;
+  this.jump = jump;
+  this.val1 = val1;
+
+  // If range is true, store the second value
+  if (range == true) {
+    this.val2 = val2;
+  }
+
+  /////////////// Create handles /////////////////
+  
+  this.$handle1 = undefined;
+  this.$handle2 = undefined;
+
+  if ( range == false) {
+    // Create the handle
+    this.$handle1 = this.createHandle(val1);
+  }
+  else {
+    // create the range highlight div
+    this.createRangeDiv();
+
+    // Create the first handle
+    this.$handle1 = this.createHandle(val1, 1);
+
+    // create the second handle
+    this.$handle2 = this.createHandle(val2, 2);
+  }
+
+} // end slider constructor
+
+//
+// function createHandle() creates a handle for the slider. It defines ARIA attributes for
+// the handle and positions it at the specified value in the slider range. if showVals is true,
+// create and position divs to display the handle value.
+//
+// @param (val integer) val is the initial value of the handle
+//
+// @param (num integer) num is the handle number. (optional)
+//
+// @return (object) returns the object pointer of the newly created handle
+//
+slider.prototype.createHandle = function(val, num) {
+
+  var id = this.id + '_handle' + (num == undefined ? '' : num);
+  var label = this.id + '_label' + (num == undefined ? '' : num);
+  var controls = this.id + '_text' + (num == undefined ? '' : num);
+  var $handle;
+
+  var handle = '<img id="' + id + '" class="' + (this.vert == true ? 'v':'h') +'sliderHandle" ' +
+    'src="slider_' + (this.vert == true ? 'v':'h') + '.png" ' + 'role="slider" ' +
+    'aria-valuemin="' + this.min +
+    '" aria-valuemax="' + this.max +
+    '" aria-valuenow="' + (val == undefined ? this.min : val) +
+           '" aria-labeledby="' + label +
+           '" aria-controls="' + controls + '" tabindex="0"></img>';
+
+  // Create the handle
+  this.$container.append(handle);
+
+  // store the handle object
+  $handle = $('#' + id);
+
+  if (this.showVals == true) {
+    var valContainer = '<div id="' + id + '_val" class="' + (this.vert == true ? 'v':'h') + 'sliderValue" 
role="presentation"></div>'
+
+    // Create the container.
+    this.$container.append(valContainer);
+  }
+
+  // store the value object
+  $handle = $('#' + id);
+
+  // position handle
+  this.positionHandle($handle, val);
+  
+  // bind handlers
+  this.bindHandlers($handle);
+  
+  return $handle;
+  
+} // end createHandle()
+
+//
+// function createRangeDiv() creates a div for the highlight of a range slider. It sets the initial top or 
left position
+// to match that of the slider container.
+//
+// @return N/A
+//
+slider.prototype.createRangeDiv = function() {
+
+  var id = this.id + '_range';
+
+  var range = '<div id="' + id + '" class="sliderRange"></div>';
+
+  // Create the range div
+  this.$container.append(range);
+
+  // Store the div object
+  this.$rangeDiv = $('#' + id);
+
+  if (this.vert == false) { // horizontal slider
+    this.$rangeDiv.css('top', this.top + 'px');
+    this.$rangeDiv.css('height', this.$container.height() + 'px');
+  }
+  else { // vertical slider
+    this.$rangeDiv.css('left', this.left + 'px');
+    this.$rangeDiv.css('width', this.$container.width() + 'px');
+  }
+  
+} // end createRangeDiv()
+
+//
+// function positionHandle() is a member function to position a handle at the specified value for the
+// slider. If showVal is true, it also positions and updates the displayed value container.
+//
+// @param($handle object) $handle is a pointer to the handle jQuery object to manipulate
+//
+// @param (val integer) val is the new value of the slider
+//
+// @return N/A
+//
+slider.prototype.positionHandle = function($handle, val) {
+
+  var handleHeight = $handle.outerHeight(); // the total height of the handle
+  var handleWidth = $handle.outerWidth(); // the total width of the handle
+  var handleOffset; // the distance from the value position for centering the handle
+  var xPos; // calculated horizontal position of the handle;
+  var yPos; // calculated vertical position of the handle;
+  var valPos; //calculated new pixel position for the value;
+
+  if (this.vert == false) {
+    // horizontal slider
+    
+    // calculate the horizontal pixel position of the specified value
+    valPos = ((val - this.min) / (this.max - this.min)) * this.width + this.left;
+
+    xPos = Math.round(valPos - (handleWidth / 2));
+    yPos = Math.round(this.top + (this.height / 2) - (handleHeight / 2));
+  }
+  else {
+    // vertical slider
+
+    // calculate the vertical pixel position of the specified value
+    valPos = ( (val - this.min) / (this.max - this.min) ) * this.height + this.top;
+
+    xPos = Math.round(this.left + (this.width / 2) - (handleWidth / 2));
+    yPos = Math.round(valPos - (handleHeight / 2));
+  }
+
+  // Set the position of the handle
+  $handle.css('top', yPos + 'px');
+  $handle.css('left', xPos + 'px');
+
+  // Set the aria-valuenow position of the handle
+  $handle.attr('aria-valuenow', val);
+
+  // Update the stored handle values
+  if (/1$/.test($handle.attr('id')) == true) {
+    // first handle
+    this.val1 = val;
+  }
+  else {
+    // second handle
+    this.val2 = val;
+  }
+
+  // if range is true, set the position of the range div
+  if (this.range == true) {
+    this.positionRangeDiv();
+  }
+
+  // if showVal is true, update the value container
+  if (this.showVals == true) {
+    this.updateValBox($handle, Math.round(valPos));
+  }
+
+} // end positionHandle()
+
+//
+// function positionRangeDiv() is a member function to reposition the range div when a handle is moved
+//
+// @return N/A
+//
+slider.prototype.positionRangeDiv = function() {
+
+  var pos; //calculated new range start position;
+  var size; //calculated new range size;
+
+  if (this.vert == false) { // Horizontal slider
+
+    // calculate the range start position
+    pos = Math.round( ((this.val1 - this.min) / (this.max - this.min)) * this.width) + this.left;
+
+    // calculate the new range width
+    size = Math.round( ((this.val2 - this.min) / (this.max - this.min)) * this.width) + this.left - pos;
+
+    // set the new range position
+    this.$rangeDiv.css('left', pos + 'px');
+
+    // set the new range width
+    this.$rangeDiv.css('width', size + 'px');
+  }
+  else {
+    // calculate the range start position
+    pos = Math.round(( (this.val1 - this.min) / (this.max - this.min)) * this.height)+ this.top;
+
+    // calculate the new range width
+    size = Math.round(( (this.val2 - this.min) / (this.max - this.min) ) * this.height) + this.top - pos;
+  
+    // set the new range position
+    this.$rangeDiv.css('top', pos + 'px');
+
+    // set the new range width
+    this.$rangeDiv.css('height', size + 'px');
+  }
+
+} // end positionRangeDiv()
+
+//
+// function updateValBox() is a member function to reposition a handle value box and update its contents
+//
+// @param ($handle object) $handle is the jQuery object of the handle that was moved
+//
+// @param (valPos integer) is the pixel position of the slider value
+//
+// @return N/A
+//
+slider.prototype.updateValBox = function($handle, valPos) {
+
+  var $valBox = $('#' + $handle.attr('id') + '_val');
+
+  var xPos; // horizontal pixel position of the box
+  var yPos; // vertical pixel position of the box
+
+  // Set the position of the handle
+  if (this.vert == false) {
+    var boxWidth = $valBox.outerWidth();
+
+    yPos = $handle.css('top');
+
+    // Adjust the horizontal position to center the value box on the value position
+    xPos = Math.round(valPos - (boxWidth / 2)) + 'px';
+
+  }
+  else {
+    var boxHeight = $valBox.outerHeight();
+
+    xPos = $handle.css('left');
+
+    // Adjust the vertical position to center the value box on the value position
+    yPos = Math.round(valPos - (boxHeight / 2)) + 'px';
+  }
+
+  // Set the position of the value box
+  $valBox.css('top', yPos);
+  $valBox.css('left', xPos);
+
+  // Set the text in the box to the handle value
+  $valBox.text($handle.attr('aria-valuenow'));
+
+} // end updateValBox()
+
+//
+// function bindHandlers() is a member function to bind event handlers to a slider handle
+//
+// @param ($handle object) $handle is the object pointer of the handle to bind handlers to
+//
+// @return N/A
+slider.prototype.bindHandlers = function($handle) {
+
+  var thisObj = this; // store the this pointer
+
+  $handle.keydown(function(e) {
+    return thisObj.handleKeyDown($handle, e);
+  });
+
+  $handle.keypress(function(e) {
+    return thisObj.handleKeyPress($handle, e);
+  });
+
+  $handle.focus(function(e) {
+    return thisObj.handleFocus($handle, e);
+  });
+
+  $handle.blur(function(e) {
+    return thisObj.handleBlur($handle, e);
+  });
+
+  $handle.mousedown(function(e) {
+    return thisObj.handleMouseDown($handle, e);
+  });
+
+} // end bindHandlers()
+
+//
+// function handleKeyDown() is a member function to process keydown events for a slider handle
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleKeyDown = function($handle, evt) {
+
+  if (evt.ctrlKey || evt.shiftKey || evt.altKey) {
+    // Do nothing
+    return true;
+  }
+
+  switch (evt.keyCode) {
+    case this.keys.home: {
+      // move the handle to the slider minimum
+      if (this.range == false) {
+        this.positionHandle($handle, this.min);
+      }
+      else {
+        if (/1$/.test($handle.attr('id')) == true) {
+          // handle 1 - move to the min value
+          this.positionHandle($handle, this.min);
+        }
+        else {
+          // handle 2 - move to the position of handle 1
+          this.positionHandle($handle, this.val1);
+        }
+      }
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+    case this.keys.end: {
+      if (this.range == false) {
+        // move the handle to the slider maximum
+        this.positionHandle($handle, this.max);
+      }
+      else {
+        if (/1$/.test($handle.attr('id')) == true) {
+          // handle 1 - move to the position of handle 2
+          this.positionHandle($handle, this.val2);
+        }
+        else {
+          // handle 2 - move to the max value
+          this.positionHandle($handle, this.max);
+        }
+      }
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+    case this.keys.pageup: {
+
+      // Decrease by jump value
+
+      var newVal = $handle.attr('aria-valuenow') - this.jump;
+      var stopVal = this.min; // where to stop moving
+      
+      if (this.range == true) {
+        // if this is handle 2, stop when we reach the value
+        // for handle 1
+        if (/2$/.test($handle.attr('id')) == true) {
+          stopVal = this.val1;
+        }
+      }
+
+      // move the handle one jump increment toward the slider minimum
+      // If value is less than stopVal, set at stopVal instead
+      this.positionHandle($handle, (newVal > stopVal ? newVal : stopVal));
+
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+    case this.keys.pagedown: {
+
+      // Increase by jump value
+
+      var newVal = parseInt($handle.attr('aria-valuenow')) + this.jump;
+      var stopVal = this.max; // where to stop moving
+
+      if (this.range == true) {
+        // if this is handle 1, stop when we reach the value
+        // for handle 2
+        if (/1$/.test($handle.attr('id')) == true) {
+          stopVal = this.val2;
+        }
+      }
+
+      // move the handle one jump increment toward the slider maximum
+      // If value is greater than maximum, set at maximum instead
+      this.positionHandle($handle, (newVal < stopVal ? newVal : stopVal));
+
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+    case this.keys.left:
+    case this.keys.up: {
+
+      var newVal = $handle.attr('aria-valuenow') - this.inc;
+      var stopVal = this.min; // where to stop moving
+      
+      if (this.range == true) {
+        // if this is handle 2, stop when we reach the value
+        // for handle 1
+        if (/2$/.test($handle.attr('id')) == true) {
+          stopVal = this.val1;
+        }
+      }
+
+      // move the handle one jump increment toward the stopVal
+      // If value is less than stopVal, set at stopVal instead
+      this.positionHandle($handle, (newVal > stopVal ? newVal : stopVal));
+
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+    case this.keys.right:
+    case this.keys.down: {
+
+      var newVal = parseInt($handle.attr('aria-valuenow')) + this.inc;
+      var stopVal = this.max; // where to stop moving
+
+      if (this.range == true) {
+        // if this is handle 1, stop when we reach the value
+        // for handle 2
+        if (/1$/.test($handle.attr('id')) == true) {
+          stopVal = this.val2;
+        }
+      }
+
+      // move the handle one increment toward the slider maximum
+      // If value is greater than maximum, set at maximum instead
+      this.positionHandle($handle, (newVal < stopVal ? newVal : stopVal));
+
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+  } // end switch
+
+  return true;
+
+} // end handleKeyDown
+
+//
+// function handleKeyPress() is a member function to process keypress events for a slider handle. Needed for
+// browsers that perform window scrolling on keypress rather than keydown events.
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleKeyPress = function($handle, evt) {
+
+  if (evt.ctrlKey || evt.shiftKey || evt.altKey) {
+    // Do nothing
+    return true;
+  }
+
+  switch (evt.keyCode) {
+    case this.keys.home:
+    case this.keys.pageup:
+    case this.keys.end:
+    case this.keys.pagedown:
+    case this.keys.left:
+    case this.keys.up:
+    case this.keys.right:
+    case this.keys.down: {
+
+      // Consume the event
+      evt.stopPropagation;
+      return false;
+      break;
+    }
+  } // end switch
+
+  return true;
+
+} // end handleKeyDown
+
+//
+// function handleFocus() is a member function to process focus events for a slider handle
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleFocus = function($handle, evt) {
+
+  $handle.attr('src', 'slider_' + (this.vert == true ? 'v' : 'h') + '-focus.png');
+  $handle.addClass('focus');
+  $handle.css('z-index', '20');
+
+  return true;
+
+} // end handleFocus()
+
+//
+// function handleBlur() is a member function to process blur events for a slider handle
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleBlur = function($handle, evt) {
+
+  $handle.attr('src', 'slider_' + (this.vert == true ? 'v' : 'h') + '.png');
+  $handle.removeClass('focus');
+  $handle.css('z-index', '10');
+
+  return true;
+
+} // end handleBlur()
+
+//
+// function handleMouseDown() is a member function to process mousedown events for a slider handle. The 
function
+// binds a mousemove handler
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleMouseDown = function($handle, evt) {
+
+  var thisObj = this; // store the this pointer
+
+  // remove focus highlight from all other slider handles on the page
+  $('.hsliderHandle').attr('src', 'slider_h.png').removeClass('focus').css('z-index', '10');
+  $('.vsliderHandle').attr('src', 'slider_v.png').removeClass('focus').css('z-index', '10');
+
+  // Set focus to the clicked handle
+  $handle.focus();
+
+  // bind a mousemove event handler to the document to capture the mouse
+  $(document).mousemove(function(e) {
+    thisObj.handleMouseMove($handle, e);
+  });
+
+  //bind a mouseup event handler to the document to capture the mouse
+  $(document).mouseup(function(e) {
+    return thisObj.handleMouseUp($handle, e);
+  });
+
+  evt.stopPropagation;
+  return false;
+
+} // end handleMouseDown()
+
+//
+// function handleMouseUp() is a member function to process mouseup events for a slider handle. The function
+// unbinds the mousemove handler
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleMouseUp = function($handle, evt) {
+
+  // unbind the event listeners to release the mouse
+  $(document).unbind('mousemove');
+  $(document).unbind('mouseup');
+
+  evt.stopPropagation;
+  return false;
+
+} // end handleMouseUp()
+
+//
+// function handleMouseMove() is a member function to process mousemove events for a slider handle.
+//
+// @param ($handle object) $handle is the object associated with the event
+//
+// @parem (evt object) evt is the event object associated witthe the event
+//
+// @return (boolean) true if propagating; false if consuming event
+//
+slider.prototype.handleMouseMove = function($handle, evt) {
+
+  var curVal = parseInt($handle.attr('aria-valuenow'));
+  var newVal;
+  var startVal = this.min;
+  var stopVal = this.max;
+
+  if (this.range == true) {
+    // if this is handle 1, set stopVal to be the value
+    // for handle 2
+    if (/1$/.test($handle.attr('id')) == true) {
+      stopVal = this.val2;
+    }
+    else {
+      // This is handle 2: Set startVal to be the value
+      // for handle 1
+      startVal = this.val1;
+    }
+  }
+
+  if (this.vert == false) {
+    // horizontal slider
+
+    // Calculate the new slider value based on the horizontal pixel position of the mouse
+    newVal = Math.round((evt.pageX - this.left) / this.width * (this.max - this.min)) + this.min;
+  }
+  else {
+    // vertical slider
+
+    // Calculate the new slider value based on the vertical pixel position of the mouse
+    newVal = Math.round((evt.pageY - this.top) / this.height * (this.max - this.min)) + this.min;
+  }
+
+  if (newVal >= startVal && newVal <= stopVal) {
+
+    // Do not move handle unless new value is a slider increment
+    if (newVal%this.inc == 0) {
+      this.positionHandle($handle, newVal);
+    }
+  }
+  else if (newVal < startVal) {
+
+    // value is less than minimum for slider - set handle to min
+    this.positionHandle($handle, startVal);
+  }
+  else if (newVal > stopVal) {
+
+    // value is greater than maximum for slider - set handle to max
+    this.positionHandle($handle, stopVal);
+  }
+
+  evt.stopPropagation;
+  return false;
+
+} // end handleMouseMove
+</script>
+<body>
+<div role="application">
+
+  <h3>Slider Example 1: A Simple Slider</h3>
+  
+  <div id="sr1_label" class="hidden">Example 1 Slider</div>
+  <div class="hslider" id="sr1"></div>  
+      
+  <h3>Slider Example 2: A Range Slider</h3>
+  
+  <div id="sr2_label1" class="hidden">Example 2 Slider Low</div>
+  <div id="sr2_label2" class="hidden">Example 2 Slider High</div>
+  <div class="hslider" id="sr2"></div>  
+
+  <h3>Slider Example 3: A Vertical Slider</h3>
+  
+  <div id="sr3_label" class="hidden">Example 3 Slider</div>
+  <div class="vslider" id="sr3"></div>  
+</div>
+</body>
+</html>
diff --git a/test/html/aria-tabpanel2.html b/test/html/aria-tabpanel2.html
new file mode 100644
index 0000000..4ce87d7
--- /dev/null
+++ b/test/html/aria-tabpanel2.html
@@ -0,0 +1,769 @@
+<html>
+<head>
+<style type="text/css">
+.tabpanel {
+  margin: 20px;
+  padding: 0;
+  height: 1%; /* IE fix for float bug */
+}
+.tablist {
+  margin: 0 0px;
+  padding: 0;
+  list-style: none;
+}
+
+.tab {
+
+  margin: .2em 1px 0 0;
+  padding: 10px;
+  height: 1em;
+  font-weight: bold;
+  background-color: #ec9;
+
+  border: 1px solid black;
+  -webkit-border-radius-topright: 5px;
+  -webkit-border-radius-topleft: 5px;
+  -moz-border-radius-topright: 5px;
+  -moz-border-radius-topleft: 5px;
+  border-radius-topright: 5px;
+  border-radius-topleft: 5px;
+
+  float: left;
+  display: inline; /* IE float bug fix */
+}
+
+.panel {
+  clear: both;
+  display: block;
+  margin: 0 0 0 0;
+  padding: 10px;
+  width: 600px;
+  border: 1px solid black;
+
+  -webkit-border-radius-topright: 10px;
+  -webkit-border-radius-bottomleft: 10px;
+  -webkit-border-radius-bottomright: 10px;
+  -moz-border-radius-topright: 10px;
+  -moz-border-radius-bottomleft: 10px;
+  -moz-border-radius-bottomright: 10px;
+  border-radius-topright: 10px;
+  border-radius-bottomleft: 10px;
+  border-radius-bottomright: 10px;
+}
+
+ul.controlList {
+  list-style-type: none;
+}
+
+li.selected {
+  color: black;
+  background-color: #fff;
+  border-bottom: 1px solid white;
+}
+
+.focus {
+  margin-top: 0;
+  height: 1.2em;
+}
+
+.accordian {
+  margin: 0;
+  float: none;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+  width: 600px;
+}
+
+.hidden {
+  position: absolute;
+  left: -300em;
+  top: -30em;
+}
+</style>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+<script type="text/javascript">
+$(document).ready(function() {
+
+  var panel1 = new tabpanel("tabpanel1", false);
+  //var panel2 = new tabpanel("accordian1", true);
+});
+
+//
+// keyCodes() is an object to contain keycodes needed for the application
+//
+function keyCodes() {
+  // Define values for keycodes
+  this.tab        = 9;
+  this.enter      = 13;
+  this.esc        = 27;
+
+  this.space      = 32;
+  this.pageup     = 33;
+  this.pagedown   = 34;
+  this.end        = 35;
+  this.home       = 36;
+
+  this.left       = 37;
+  this.up         = 38;
+  this.right      = 39;
+  this.down       = 40; 
+
+} // end keyCodes
+
+//
+// tabpanel() is a class constructor to create a ARIA-enabled tab panel widget.
+//
+// @param (id string) id is the id of the div containing the tab panel.
+//
+// @param (accordian boolean) accordian is true if the tab panel should operate
+//         as an accordian; false if a tab panel
+//
+// @return N/A
+//
+// Usage: Requires a div container and children as follows:
+//
+//         1. tabs/accordian headers have class 'tab'
+//
+//         2. panels are divs with class 'panel'
+//
+function tabpanel(id, accordian) {
+
+  // define the class properties
+  
+  this.panel_id = id; // store the id of the containing div
+  this.accordian = accordian; // true if this is an accordian control
+  this.$panel = $('#' + id);  // store the jQuery object for the panel
+  this.keys = new keyCodes(); // keycodes needed for event handlers
+  this.$tabs = this.$panel.find('.tab'); // Array of panel tabs.
+  this.$panels = this.$panel.children('.panel'); // Array of panel.
+
+  // Bind event handlers
+  this.bindHandlers();
+
+  // Initialize the tab panel
+  this.init();
+
+} // end tabpanel() constructor
+
+//
+// Function init() is a member function to initialize the tab/accordian panel. Hides all panels. If a tab
+// has the class 'selected', makes that panel visible; otherwise, makes first panel visible.
+//
+// @return N/A
+//
+tabpanel.prototype.init = function() {
+  var $tab; // the selected tab - if one is selected
+
+  // add aria attributes to the panel container
+  this.$panel.attr('aria-multiselectable', this.accordian);
+
+  // add aria attributes to the panels
+  this.$panels.attr('aria-hidden', 'true');
+
+  // hide all the panels
+  this.$panels.hide();
+
+  // get the selected tab
+  $tab = this.$tabs.filter('.selected');
+
+  if ($tab == undefined) {
+    $tab = this.$tabs.first();
+    $tab.addClass('selected');
+  }
+
+  // show the panel that the selected tab controls and set aria-hidden to false
+  this.$panel.find('#' + $tab.attr('aria-controls')).show().attr('aria-hidden', 'false');
+
+} // end init()
+
+//
+// Function switchTabs() is a member function to give focus to a new tab or accordian header.
+// If it's a tab panel, the currently displayed panel is hidden and the panel associated with the new tab
+// is displayed.
+//
+// @param ($curTab obj) $curTab is the jQuery object of the currently selected tab
+//
+// @param ($newTab obj) $newTab is the jQuery object of new tab to switch to
+//
+// @param (activate boolean) activate is true if focus should be set on an element in the panel; false if on 
tab
+//
+// @return N/A
+//
+tabpanel.prototype.switchTabs = function($curTab, $newTab) {
+
+  // Remove the highlighting from the current tab
+  $curTab.removeClass('selected');
+  $curTab.removeClass('focus');
+
+  // remove tab from the tab order
+  $curTab.attr('tabindex', '-1');
+
+  // update the aria attributes
+  
+  // Highlight the new tab
+  $newTab.addClass('selected');
+
+  // If this is a tab panel, swap displayed tabs
+  if (this.accordian == false) {
+    // hide the current tab panel and set aria-hidden to true
+    this.$panel.find('#' + $curTab.attr('aria-controls')).hide().attr('aria-hidden', 'true');
+
+    // show the new tab panel and set aria-hidden to false
+    this.$panel.find('#' + $newTab.attr('aria-controls')).show().attr('aria-hidden', 'false');
+  }
+
+  // Make new tab navigable
+  $newTab.attr('tabindex', '0');
+
+  // give the new tab focus
+  $newTab.focus();
+
+} // end switchTabs()
+
+//
+// Function togglePanel() is a member function to display or hide the panel associated with an accordian 
header
+//
+// @param ($tab obj) $tab is the jQuery object of the currently selected tab
+//
+// @return N/A
+//
+tabpanel.prototype.togglePanel = function($tab) {
+
+  $panel = this.$panel.find('#' + $tab.attr('aria-controls'));
+
+  if ($panel.attr('aria-hidden') == 'true') {
+    $panel.slideDown(100);
+    $panel.attr('aria-hidden', 'false');
+  }
+  else {
+    $panel.slideUp(100);
+    $panel.attr('aria-hidden', 'true');
+  }
+} // end togglePanel()
+
+//
+// Function bindHandlers() is a member function to bind event handlers for the tabs
+//
+// @return N/A
+//
+tabpanel.prototype.bindHandlers = function() {
+
+  var thisObj = this; // Store the this pointer for reference
+
+  //////////////////////////////
+  // Bind handlers for the tabs / accordian headers
+
+  // bind a tab keydown handler
+  this.$tabs.keydown(function(e) {
+    return thisObj.handleTabKeyDown($(this), e);
+  });
+
+  // bind a tab keypress handler
+  this.$tabs.keypress(function(e) {
+    return thisObj.handleTabKeyPress($(this), e);
+  });
+
+  // bind a tab click handler
+  this.$tabs.click(function(e) {
+    return thisObj.handleTabClick($(this), e);
+  });
+
+  // bind a tab focus handler
+  this.$tabs.focus(function(e) {
+    return thisObj.handleTabFocus($(this), e);
+  });
+
+  // bind a tab blur handler
+  this.$tabs.blur(function(e) {
+    return thisObj.handleTabBlur($(this), e);
+  });
+
+  /////////////////////////////
+  // Bind handlers for the panels
+  
+  // bind a keydown handlers for the panel focusable elements
+  this.$panels.keydown(function(e) {
+    return thisObj.handlePanelKeyDown($(this), e);
+  });
+
+  // bind a keypress handler for the panel
+  this.$panels.keypress(function(e) {
+    return thisObj.handlePanelKeyPress($(this), e);
+  });
+
+} // end bindHandlers()
+
+//
+// Function handleTabKeyDown() is a member function to process keydown events for a tab
+//
+// @param ($tab obj) $tab is the jquery object of the tab being processed
+//
+// @paran (e obj) e is the associated event object
+//
+// @return (boolean) Returns true if propagating; false if consuming event
+//
+tabpanel.prototype.handleTabKeyDown = function($tab, e) {
+
+  if (e.altKey) {
+    // do nothing
+    return true;
+  }
+
+  switch (e.keyCode) {
+    case this.keys.enter:
+    case this.keys.space: {
+
+      // Only process if this is an accordian widget
+      if (this.accordian == true) {
+        // display or collapse the panel
+        this.togglePanel($tab);
+
+        e.stopPropagation();
+        return false;
+      }
+
+      return true;
+    }
+    case this.keys.left:
+    case this.keys.up: {
+
+      var thisObj = this;
+      var $prevTab; // holds jQuery object of tab from previous pass
+      var $newTab; // the new tab to switch to
+
+      if (e.ctrlKey) {
+        // Ctrl+arrow moves focus from panel content to the open
+        // tab/accordian header.
+      }
+      else {
+        var curNdx = this.$tabs.index($tab);
+
+        if (curNdx == 0) {
+          // tab is the first one:
+          // set newTab to last tab
+          $newTab = this.$tabs.last();
+        }
+        else {
+          // set newTab to previous
+          $newTab = this.$tabs.eq(curNdx - 1);
+        }
+
+        // switch to the new tab
+        this.switchTabs($tab, $newTab);
+      }
+
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.right:
+    case this.keys.down: {
+
+      var thisObj = this;
+      var foundTab = false; // set to true when current tab found in array
+      var $newTab; // the new tab to switch to
+
+      var curNdx = this.$tabs.index($tab);
+
+      if (curNdx == this.$tabs.last().index()) {
+        // tab is the last one:
+        // set newTab to first tab
+        $newTab = this.$tabs.first();
+      }
+      else {
+        // set newTab to next tab
+        $newTab = this.$tabs.eq(curNdx + 1);
+      }
+
+      // switch to the new tab
+      this.switchTabs($tab, $newTab);
+
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.home: {
+
+      // switch to the first tab
+      this.switchTabs($tab, this.$tabs.first());
+
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.end: {
+
+      // switch to the last tab
+      this.switchTabs($tab, this.$tabs.last());
+
+      e.stopPropagation();
+      return false;
+    }
+  }
+} // end handleTabKeyDown()
+
+//
+// Function handleTabKeyPress() is a member function to process keypress events for a tab.
+//
+//
+// @param ($tab obj) $tab is the jquery object of the tab being processed
+//
+// @paran (e obj) e is the associated event object
+//
+// @return (boolean) Returns true if propagating; false if consuming event
+//
+tabpanel.prototype.handleTabKeyPress = function($tab, e) {
+
+  if (e.altKey) {
+    // do nothing
+    return true;
+  }
+
+  switch (e.keyCode) {
+    case this.keys.enter:
+    case this.keys.space:
+    case this.keys.left:
+    case this.keys.up:
+    case this.keys.right:
+    case this.keys.down:
+    case this.keys.home:
+    case this.keys.end: {
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.pageup:
+    case this.keys.pagedown: {
+
+      // The tab keypress handler must consume pageup and pagedown
+      // keypresses to prevent Firefox from switching tabs
+      // on ctrl+pageup and ctrl+pagedown
+
+      if (!e.ctrlKey) {
+        return true;
+      }
+
+      e.stopPropagation();
+      return false;
+    }
+  }
+
+  return true;
+
+} // end handleTabKeyPress()
+
+//
+// Function handleTabClick() is a member function to process click events for tabs
+//
+// @param ($tab object) $tab is the jQuery object of the tab being processed
+//
+// @paran (e object) e is the associated event object
+//
+// @return (boolean) returns true
+//
+tabpanel.prototype.handleTabClick = function($tab, e) {
+
+  // Remove the highlighting from all tabs
+  this.$tabs.removeClass('selected');
+
+  // remove all tabs from the tab order
+  this.$tabs.attr('tabindex', '-1');
+
+  // hide all tab panels
+  this.$panels.hide();
+  
+  // Highlight the clicked tab
+  $tab.addClass('selected');
+
+  // show the clicked tab panel
+  this.$panel.find('#' + $tab.attr('aria-controls')).show();
+
+  // make clicked tab navigable
+  $tab.attr('tabindex', '0');
+
+  // give the tab focus
+  $tab.focus();
+
+  return true;
+
+} // end handleTabClick()
+
+//
+// Function handleTabFocus() is a member function to process focus events for tabs
+//
+// @param ($tab object) $tab is the jQuery object of the tab being processed
+//
+// @paran (e object) e is the associated event object
+//
+// @return (boolean) returns true
+//
+tabpanel.prototype.handleTabFocus = function($tab, e) {
+
+  // Add the focus class to the tab
+  $tab.addClass('focus');
+
+  return true;
+
+} // end handleTabFocus()
+
+//
+// Function handleTabBlur() is a member function to process blur events for tabs
+//
+// @param ($tab object) $tab is the jQuery object of the tab being processed
+//
+// @paran (e object) e is the associated event object
+//
+// @return (boolean) returns true
+//
+tabpanel.prototype.handleTabBlur = function($tab, e) {
+
+  // Remove the focus class to the tab
+  $tab.removeClass('focus');
+
+  return true;
+
+} // end handleTabBlur()
+
+
+/////////////////////////////////////////////////////////
+// Panel Event handlers
+//
+
+//
+// Function handlePanelKeyDown() is a member function to process keydown events for a panel
+//
+// @param ($elem obj) $elem is the jquery object of the element being processed
+//
+// @paran (e obj) e is the associated event object
+//
+// @return (boolean) Returns true if propagating; false if consuming event
+//
+tabpanel.prototype.handlePanelKeyDown = function($elem, e) {
+
+  if (e.altKey) {
+    // do nothing
+    return true;
+  }
+
+  switch (e.keyCode) {
+    case this.keys.esc: {
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.left:
+    case this.keys.up: {
+
+      if (!e.ctrlKey) {
+        // do not process
+        return true;
+      }
+  
+      // get the jQuery object of the tab
+      var $tab = $('#' + $elem.attr('aria-labeledby'));
+
+      // Move focus to the tab
+      $tab.focus();
+
+      e.stopPropagation();
+      return false;
+    }
+    case this.keys.pageup: {
+
+      var $newTab;
+
+      if (!e.ctrlKey) {
+        // do not process
+        return true;
+      }
+
+      // get the jQuery object of the tab
+      var $tab = this.$tabs.filter('.selected');
+
+      // get the index of the tab in the tab list
+      var curNdx = this.$tabs.index($tab);
+
+      if (curNdx == 0) {
+        // this is the first tab, set focus on the last one
+        $newTab = this.$tabs.last();
+      }
+      else {
+        // set focus on the previous tab
+        $newTab = this.$tabs.eq(curNdx - 1);
+      }
+
+      // switch to the new tab
+      this.switchTabs($tab, $newTab);
+
+      e.stopPropagation();
+      e.preventDefault();
+      return false;
+    }
+    case this.keys.pagedown: {
+
+      var $newTab;
+
+      if (!e.ctrlKey) {
+        // do not process
+        return true;
+      }
+
+      // get the jQuery object of the tab
+      var $tab = $('#' + $elem.attr('aria-labeledby'));
+
+      // get the index of the tab in the tab list
+      var curNdx = this.$tabs.index($tab);
+
+      if (curNdx == this.$tabs.last().index()) {
+        // this is the last tab, set focus on the first one
+        $newTab = this.$tabs.first();
+      }
+      else {
+        // set focus on the next tab
+        $newTab = this.$tabs.eq(curNdx + 1);
+      }
+
+      // switch to the new tab
+      this.switchTabs($tab, $newTab);
+
+      e.stopPropagation();
+      e.preventDefault();
+      return false;
+    }
+  }
+
+  return true;
+
+} // end handlePanelKeyDown()
+
+//
+// Function handlePanelKeyPress() is a member function to process keypress events for a panel
+//
+// @param ($elem obj) $elem is the jquery object of the element being processed
+//
+// @paran (e obj) e is the associated event object
+//
+// @return (boolean) Returns true if propagating; false if consuming event
+//
+tabpanel.prototype.handlePanelKeyPress = function($elem, e) {
+
+  if (e.altKey) {
+    // do nothing
+    return true;
+  }
+
+  if (e.ctrlKey && (e.keyCode == this.keys.pageup || e.keyCode == this.keys.pagedown)) {
+      e.stopPropagation();
+      e.preventDefault();
+      return false;
+  }
+
+  switch (e.keyCode) {
+    case this.keys.esc: {
+      e.stopPropagation();
+      e.preventDefault();
+      return false;
+    }
+  }
+
+  return true;
+
+} // end handlePanelKeyPress()
+
+// focusable is a small jQuery extension to add a :focusable selector. It is used to
+// get a list of all focusable elements in a panel. Credit to ajpiano on the jQuery forums.
+//
+$.extend($.expr[':'], {
+  focusable: function(element) {
+    var nodeName = element.nodeName.toLowerCase();
+    var tabIndex = $(element).attr('tabindex');
+
+    // the element and all of its ancestors must be visible
+    if (($(element)[nodeName == 'area' ? 'parents' : 'closest'](':hidden').length) == true) {
+      return false;
+    }
+
+    // If tabindex is defined, its value must be greater than 0
+    if (!isNaN(tabIndex) && tabIndex < 0) {
+      return false;
+    }
+
+    // if the element is a standard form control, it must not be disabled
+    if (/input|select|textarea|button|object/.test(nodeName) == true) {
+
+             return !element.disabled;
+    }
+
+    // if the element is a link, href must be defined
+    if ((nodeName == 'a' ||  nodeName == 'area') == true) {
+
+      return (element.href.length > 0);
+    }
+             
+    // this is some other page element that is not normally focusable.
+    return false;
+  }
+});
+</script>
+</head>
+<body>
+<div role="application">
+
+<h2>Happy Time Pizza On-line Ordering System</h2>
+
+<form>
+<div id="tabpanel1" class="tabpanel">
+
+  <ul class="tablist" role="tablist">
+    <li id="tab1" class="tab selected" aria-controls="panel1" role="tab">Crust</li>
+    <li id="tab2" class="tab" aria-controls="panel2" role="tab">Veggies</li>
+    <li id="tab3" class="tab" aria-controls="panel3" role="tab">Carnivore</li>
+    <li id="tab4" class="tab" aria-controls="panel4" role="tab">Delivery</li>
+  </ul>
+
+  <div id="panel1" class="panel" aria-labeledby="tab1" role="tabpanel">
+    <h3>Select Crust</h3>
+     
+          <ul class="controlList">
+            <li><label><input type="radio" name="crust" value="crust1" />Deep Dish</label></li>
+            <li><label><input type="radio" name="crust" value="crust2" checked="checked" />Thick and 
cheesy</label></li>
+            <li><label><input type="radio" name="crust" value="crust3" />Thick and spicy</label></li>
+            <li><label><input type="radio" name="crust" value="crust4" />Thin</label></li>
+         </ul>
+  </div>
+
+  <div id="panel2" class="panel" aria-labeledby="tab2" role="tabpanel">
+    <h3>Select Vegetables</h3>  
+     
+         <ul class="controlList">
+            <li><label><input type="checkbox" name="veg" value="black olives" />Black Olives</label></li>
+            <li><label><input type="checkbox" name="veg" value="green olives" />Green Olives</label></li>
+            <li><label><input type="checkbox" name="veg" value="green peppers" />Green Peppers</label></li>
+            <li><label><input type="checkbox" name="veg" value="mushrooms" />Mushrooms</label></li>
+            <li><label><input type="checkbox" name="veg" value="onions" />Onions</label></li>
+            <li><label><input type="checkbox" name="veg" value="pineapple" />Pineapple</label></li>
+         </ul>
+  </div>
+
+  <div id="panel3" class="panel" aria-labeledby="tab3" role="tabpanel">
+    <h3>Select Carnivore Options</h3>
+     
+          <ul class="controlList">
+            <li><label><input type="checkbox" name="meat" value="pepperoni" />Pepperoni</label></li>
+            <li><label><input type="checkbox" name="meat" value="sausage" />Italian Sausage</label></li>
+            <li><label><input type="checkbox" name="meat" value="ham" />Ham</label></li>
+            <li><label><input type="checkbox" name="meat" value="hamburger" />Hamburger</label></li>
+          </ul>
+  </div>
+
+  <div id="panel4" class="panel" aria-labeledby="tab4" role="tabpanel">
+     <h3>Select Delivery Method</h3>
+     
+    <ul class="controlList">
+      <li><label><input type="radio" name="delivery" value="delivery1" checked="checked" 
/>Delivery</label></li>
+      <li><label><input type="radio" name="delivery" value="delivery2" />Eat in</label></li>
+      <li><label><input type="radio" name="delivery" value="delivery3" />Carry out</label></li>
+      <li><label><input type="radio" name="delivery" value="delivery4" />Overnight mail</label></li>
+    </ul>
+  </div>
+</div>
+</form>
+</div>
+</body>
+</html>
diff --git a/test/html/aria-tree.html b/test/html/aria-tree.html
new file mode 100644
index 0000000..ce7a325
--- /dev/null
+++ b/test/html/aria-tree.html
@@ -0,0 +1,672 @@
+<html>
+<head>
+<style type="text/css">
+ul.tree { 
+  width: 10em; 
+} 
+ul.tree, ul.tree ul { 
+  list-style: none; 
+  margin: 0; 
+  padding-left: 20px; 
+  font-weight: normal; 
+  background-color: white; 
+  color: black; 
+} 
+
+ul.tree li { 
+  margin-left: 17px; 
+} 
+
+ul.tree li.groupHeader { 
+  font-weight: bold; 
+  margin-left: 0px; 
+} 
+
+img.headerImg { 
+  margin-right: 5px; 
+} 
+
+li.focus { 
+  color: white; 
+  background: black; 
+} 
+</style>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";></script>
+<script type="text/javascript">
+var g_focusHandled = false; // set to true if focus is handled 
+
+// 
+// Function resetFocusFlag() is a callback to reset the focusHandled flag. This is 
+// called by the timer set in the treeview focus handler 
+// 
+function resetFocusFlag() { 
+  g_focusHandled = false; 
+} 
+
+$(document).ready(function() { 
+
+  var treeviewApp = new treeview('tree1'); 
+
+}); // end ready 
+
+// 
+// Function keyCodes() is an object to define keycodes for the application 
+// 
+function keyCodes() { 
+
+  this.enter      = 13; 
+  this.space      = 32; 
+
+  this.pageup     = 33; 
+  this.pagedown   = 34; 
+  this.end        = 35; 
+  this.home       = 36; 
+  this.left       = 37; 
+  this.up         = 38; 
+  this.right      = 39; 
+  this.down       = 40; 
+  this.asterisk   = 106; 
+
+} // end keyCodes() 
+
+// 
+// Function treeview() is a class constructor for a treeview widget. The widget binds to an 
+// unordered list. The top-level <ul> must have role='tree'. All list items must have role='treeitem'. 
+// 
+// Tree groups must be embedded lists within the listitem that heads the group. the top <ul> of a group 
+// must have role='group'. aria-expanded is used to indicate whether a group is expanded or collapsed. This 
+// property must be set on the listitem the encapsulates the group. 
+// 
+// @param (treeID string) treeID is the html id of the top-level <ul> of the list to bind the widget to 
+// 
+// @return N/A 
+// 
+function treeview(treeID) { 
+
+  // define the object properties 
+  this.$id = $('#' + treeID); 
+  this.$listitems = this.$id.find('li'); // an array of list items 
+  this.$groups = undefined; // an array of the listitems that function as group headers 
+  this.$visibleItems = undefined; // an array of currently visible listitems (including headers) 
+  this.focusHandled = false; // Set to true when a focus event is handled and reset after a small delay 
+
+  this.keys = new keyCodes(); 
+
+  // initialize the treeview 
+  this.init(); 
+
+  // bind event handlers 
+  this.bindHandlers(); 
+
+} // end treeview() constructor 
+
+// 
+// Function init() is a member function to initialize the treeview widget. It traverses the tree, 
identifying 
+// which listitems are headers for groups and applying initial collapsed are expanded styling 
+// 
+// @return N/A 
+// 
+treeview.prototype.init = function() { 
+
+  var thisObj = this; 
+
+  // iterate through the tree and apply the groupHeader class and styling to the group headers 
+  this.$id.find('li').each (function(index) { 
+
+    var $group = $(this).children('ul'); 
+
+    if ($group.length > 0) { 
+      // this listitem is a group header 
+
+      // Apply the group header styling 
+      $(this).addClass('groupHeader'); 
+
+      // insert the header image. Note: this method allows the widget to degrade gracefully 
+      // if javascript is disabled or there is some other error. 
+      $(this).prepend('<img class="headerImg" src="treeExpanded.gif" />'); 
+
+      // If the aria-expanded is false, hide the group and display the collapsed state image 
+      if ($(this).attr('aria-expanded') == 'false') { 
+        $group.hide(); 
+        $(this).find('img').attr('src', 'treeContracted.gif'); 
+      } 
+    } 
+  }); 
+
+  // create the group and initial visible item array 
+  this.$groups = $('li.groupHeader'); 
+  this.$visibleItems = this.$id.find('li:visible'); 
+
+} // end init() 
+
+// 
+// Function expandGroup() is a member function to expand a collapsed group 
+// 
+// @param($id object) $id is the jquery id of the group header of the group to expand 
+// 
+// @param(focus boolean) focus is true if the group header has focus, false otherwise 
+// 
+// @return N/A 
+// 
+treeview.prototype.expandGroup = function($id, focus) { 
+
+  var $group = $id.children('ul'); 
+
+  // expand the group 
+  $group.show(); 
+
+  $id.attr('aria-expanded', 'true'); 
+
+  if (focus == true) { 
+    $id.children('img').attr('src', 'treeExpandedFocus.gif'); 
+  } 
+  else { 
+    $id.children('img').attr('src', 'treeExpanded.gif'); 
+  } 
+
+  // refresh the list of visible items 
+  this.$visibleItems = this.$id.find('li:visible'); 
+
+} // end expandGroup() 
+
+// 
+// Function collapseGroup() is a member function to collapse an expanded group 
+// 
+// @param($id object) $id is the jquery id of the group header of the group to collapse 
+// 
+// @param(focus boolean) focus is true if the group header has focus, false otherwise 
+// 
+// @return N/A 
+// 
+treeview.prototype.collapseGroup = function($id, focus) { 
+
+  var $group = $id.children('ul'); 
+
+  // collapse the group 
+  $group.hide(); 
+
+  $id.attr('aria-expanded', 'false'); 
+
+  if (focus == true) { 
+    $id.children('img').attr('src', 'treeContractedFocus.gif'); 
+  } 
+  else { 
+    $id.children('img').attr('src', 'treeContracted.gif'); 
+  } 
+
+  // refresh the list of visible items 
+  this.$visibleItems = this.$id.find('li:visible'); 
+
+} // end collapseGroup() 
+
+// 
+// Function toggleGroup() is a member function to toggle the display state of a group 
+// 
+// @param($id object) $id is the jquery id of the group header of the group to toggle 
+// 
+// @param(focus boolean) focus is true if the group header has focus, false otherwise 
+// 
+// @return N/A 
+// 
+treeview.prototype.toggleGroup = function($id, focus) { 
+
+  var $group = $id.children('ul'); 
+
+  if ($id.attr('aria-expanded') == 'true') { 
+    // collapse the group 
+    this.collapseGroup($id, focus); 
+  } 
+  else { 
+    // expand the group 
+    this.expandGroup($id, focus); 
+  } 
+
+} // end toggleGroup() 
+
+// 
+// Function bindHandlers() is a member function to bind event handlers to the listitems 
+// 
+// return N/A 
+// 
+treeview.prototype.bindHandlers = function() { 
+
+  var thisObj = this; 
+
+  // bind a dblclick handler to the group headers 
+  this.$groups.dblclick(function(e) { 
+    return thisObj.handleDblClick($(this), e); 
+  }); 
+
+  // bind a click handler 
+  this.$listitems.click(function(e) { 
+    return thisObj.handleClick($(this), e); 
+  }); 
+
+  // bind a keydown handler 
+  this.$listitems.keydown(function(e) { 
+    return thisObj.handleKeyDown($(this), e); 
+  }); 
+
+  // bind a keypress handler 
+  this.$listitems.keypress(function(e) { 
+    return thisObj.handleKeyPress($(this), e); 
+  }); 
+
+  // bind a focus handler 
+  this.$listitems.focus(function(e) { 
+    return thisObj.handleFocus($(this), e); 
+  }); 
+
+  // bind a blur handler 
+  this.$listitems.blur(function(e) { 
+    return thisObj.handleBlur($(this), e); 
+  }); 
+
+} // end bindHandlers() 
+
+// 
+// Function doHighlight() is a member function to remove the highlighting from 
+// other treeview items and apply it to the passed element 
+// 
+// @param ($id object) $id is the jQuery object of the element to highlight 
+// 
+// @param (isHeader boolean) isHeader is true if $id points to a group header 
+// 
+// @return N/A 
+// 
+treeview.prototype.doHighlight = function($id, isHeader) { 
+
+  // remove the focus highlighting from the treeview items 
+  // and remove them from the tab order. 
+  this.$listitems.removeClass('focus').attr('tabindex', '-1'); 
+
+  // remove the focus image from group headers 
+  this.$groups.each(function() { 
+    // add the focus image 
+    if ($(this).attr('aria-expanded') == 'true') { 
+      $(this).children('img').attr('src', 'treeExpanded.gif'); 
+    } 
+    else { 
+      $(this).children('img').attr('src', 'treeContracted.gif'); 
+    } 
+  }); 
+
+  if (isHeader == true) { 
+    // add the focus image 
+    if ($id.attr('aria-expanded') == 'true') { 
+      $id.children('img').attr('src', 'treeExpandedFocus.gif'); 
+    } 
+    else { 
+      $id.children('img').attr('src', 'treeContractedFocus.gif'); 
+    } 
+  } 
+
+
+  // apply the focus highlighting and place the element in the tab order 
+  $id.addClass('focus').attr('tabindex', '0'); 
+
+} // end doHighlight() 
+
+// 
+// Function handleKeyDown() is a member function to process keydown events for the treeview items 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns false if consuming event; true if not 
+// 
+treeview.prototype.handleKeyDown = function($id, e) { 
+
+  var curNdx = this.$visibleItems.index($id); 
+  var isHeader = false; 
+
+  // determine if this is a group header 
+  if (this.$groups.index($prev) != -1) { 
+    isHeader = true; 
+  } 
+
+  if (e.altKey || e.ctrlKey || e.shiftKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  switch (e.keyCode) { 
+    case this.keys.home: { 
+      this.$groups.first().focus(); 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.end: { 
+      this.$visibleItems.last().focus(); 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.enter: { 
+
+      if (isHeader == false) { 
+        // do nothing 
+        return true; 
+      } 
+
+      this.toggleGroup($id, true); 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.left: { 
+       
+      if (isHeader == false) { 
+        // do nothing 
+        return true; 
+      } 
+
+      if ($id.attr('aria-expanded') == 'true') { 
+        this.collapseGroup($id, true); 
+      } 
+      else { 
+        // move to previous group header 
+        var prevNdx = this.$groups.index($id) - 1; 
+
+        if (prevNdx >= 0) { 
+          var $prev = this.$groups.eq(prevNdx); 
+          var parentFound = false; 
+
+          while (parentFound == false) { 
+            if ($prev.find('#' + $id.attr('id')).length > 0) { 
+              parentFound = true; 
+              $prev.focus(); 
+              break; 
+            } 
+            else { 
+              // decrement prevNdx to reference the previous 
+              // group header in the $groups array 
+              prevNdx--; 
+
+              $prev = this.$groups.eq(prevNdx); 
+
+              if (prevNdx < 0) { 
+                // no parent group header 
+                break; 
+              } 
+            } 
+
+          } // end while 
+        } 
+      } 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.right: { 
+       
+      if (isHeader == false) { 
+        // do nothing 
+        return true; 
+      } 
+
+      if ($id.attr('aria-expanded') == 'false') { 
+        this.expandGroup($id, true); 
+      } 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.up: { 
+
+      if (curNdx > 0) { 
+        var $prev = this.$visibleItems.eq(curNdx - 1); 
+
+        $prev.focus(); 
+      } 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.down: { 
+
+      if (curNdx < this.$visibleItems.length - 1) { 
+        var $next = this.$visibleItems.eq(curNdx + 1); 
+
+        $next.focus(); 
+      } 
+      e.stopPropagation(); 
+      return false; 
+    } 
+    case this.keys.asterisk: { 
+      // expand all groups 
+
+      var thisObj = this; 
+
+      this.$groups.each(function() { 
+        thisObj.expandGroup($(this), false); 
+      }); 
+
+      e.stopPropagation(); 
+      return false; 
+    } 
+  } 
+
+  return true; 
+
+} // end handleKeyDown 
+
+// 
+// Function handleKeyPress() is a member function to process keypress events for the treeview items 
+// This function is needed for browsers, such as Opera, that perform window manipulation on kepress events 
+// rather than keydown. The function simply consumes the event. 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns false if consuming event; true if not 
+// 
+treeview.prototype.handleKeyPress = function($id, e) { 
+
+  if (e.altKey || e.ctrlKey || e.shiftKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  switch (e.keyCode) { 
+    case this.keys.enter: 
+    case this.keys.home: 
+    case this.keys.end: 
+    case this.keys.left: 
+    case this.keys.right: 
+    case this.keys.up: 
+    case this.keys.down: { 
+      e.stopPropagation(); 
+      return false; 
+    } 
+  } 
+
+  return true; 
+
+} // end handleKeyPress 
+
+// 
+// Function handleDblClick() is a member function to process double-click events for group headers. 
+// Double-click expands or collapses a group. 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns false if consuming event; true if not 
+// 
+treeview.prototype.handleDblClick = function($id, e) { 
+
+  if (e.altKey || e.ctrlKey || e.shiftKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  // apply the focus highlighting 
+  this.doHighlight($id, true); 
+
+  // expand or collapse the group 
+  this.toggleGroup($id, true); 
+
+  e.stopPropagation(); 
+  return false; 
+
+} // end handleDblClick 
+
+// 
+// Function handleClick() is a member function to process click events. 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns false if consuming event; true if not 
+// 
+treeview.prototype.handleClick = function($id, e) { 
+
+  if (e.altKey || e.ctrlKey || e.shiftKey) { 
+    // do nothing 
+    return true; 
+  } 
+
+  if (this.$groups.index($id) == -1) { 
+    // this is a list item 
+
+    // apply the focus highlighting 
+    this.doHighlight($id, false); 
+  } 
+  else { 
+    // this is a group header 
+
+    // apply the focus highlighting 
+    this.doHighlight($id, true); 
+  } 
+
+  e.stopPropagation(); 
+  return false; 
+
+} // end handleClick 
+
+// 
+// Function handleFocus() is a member function to process focus events. 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns true 
+// 
+treeview.prototype.handleFocus = function($id, e) { 
+
+  // only process the event if the focusHandled flag is false 
+  if (g_focusHandled == false) { 
+
+    // prevent encapsulating group headers from responding to 
+    // the focus event. 
+    g_focusHandled = true; 
+   
+    if (this.$groups.index($id) == -1) { 
+      this.doHighlight($id, false); 
+    } 
+    else { 
+      // this is a group header 
+      this.doHighlight($id, true); 
+    } 
+
+    window.setTimeout(resetFocusFlag, 10); 
+  } 
+
+  return true; 
+
+} // end handleFocus 
+
+// 
+// Function handleBlur() is a member function to process blur events. 
+// 
+// @param ($id object) $id is the jQuery id of the group header firing event 
+// 
+// @param (e object) e is the associated event object 
+// 
+// @return (boolean) returns true 
+// 
+treeview.prototype.handleBlur = function($id, e) { 
+
+  if (this.$groups.index($id) != -1) { 
+    // this is a group header 
+
+    // remove the focus image 
+    if ($id.attr('aria-expanded') == 'true') { 
+      $id.children('img').attr('src', 'treeExpanded.gif'); 
+    } 
+    else { 
+      $id.children('img').attr('src', 'treeContracted.gif'); 
+    } 
+  } 
+
+  // remove the focus highlighting 
+  $id.removeClass('focus'); 
+
+  return true; 
+
+} // end handleBlur 
+</script>
+</head> 
+<body>
+<div role="application"> 
+<h2 id="label_1">Foods</h2> 
+<ul id="tree1" class="tree" role="tree" aria-labelledby="label_1"> 
+  <li id="fruits" role="treeitem" tabindex="0" aria-expanded="true">Fruits 
+    <ul role="group"> 
+      <li id="oranges" role="treeitem" tabindex="-1">Oranges</li> 
+      <li id="pinapples" role="treeitem" tabindex="-1">Pineapples</li> 
+      <li id="apples" role="treeitem" tabindex="-1" aria-expanded="false">Apples 
+        <ul role="group"> 
+          <li id="macintosh" role="treeitem" tabindex="-1">Macintosh</li> 
+          <li id="granny_smith" role="treeitem" tabindex="-1" aria-expanded="false">Granny Smith 
+            <ul role="group"> 
+              <li id="Washington" role="treeitem" tabindex="-1">Washington State</li> 
+              <li id="Michigan" role="treeitem" tabindex="-1">Michigan</li> 
+              <li id="New_York" role="treeitem" tabindex="-1">New York</li> 
+            </ul> 
+          </li> 
+          <li id="fuji" role="treeitem" tabindex="-1">Fuji</li> 
+        </ul> 
+      </li> 
+      <li id="bananas" role="treeitem" tabindex="-1">Bananas</li>     
+      <li id="pears" role="treeitem" tabindex="-1">Pears</li>     
+    </ul> 
+  </li> 
+  <li id="vegetables" role="treeitem" tabindex="-1" aria-expanded="true">Vegetables 
+    <ul role="group"> 
+      <li id="broccoli" role="treeitem" tabindex="-1">Broccoli</li> 
+      <li id="carrots" role="treeitem" tabindex="-1">Carrots</li> 
+      <li id="lettuce" role="treeitem" tabindex="-1" aria-expanded="false">Lettuce 
+      <ul role="group"> 
+          <li id="romaine" role="treeitem" tabindex="-1">Romaine</li> 
+          <li id="iceberg" role="treeitem" tabindex="-1">Iceberg</li> 
+          <li id="butterhead" role="treeitem" tabindex="-1">Butterhead</li> 
+      </ul> 
+      </li> 
+      <li id="spinach" role="treeitem" tabindex="-1">Spinach</li>     
+      <li id="squash" role="treeitem" tabindex="-1" aria-expanded="true">Squash 
+        <ul role="group" > 
+          <li id="acorn" role="treeitem" tabindex="-1">Acorn</li> 
+          <li id="ambercup" role="treeitem" tabindex="-1">Ambercup</li> 
+          <li id="autumn_cup" role="treeitem" tabindex="-1">Autumn Cup</li> 
+          <li id="hubbard" role="treeitem" tabindex="-1">Hubbard</li> 
+          <li id="kobacha" role="treeitem" tabindex="-1">Kabocha</li> 
+          <li id="butternut" role="treeitem" tabindex="-1">Butternut</li> 
+          <li id="spaghetti" role="treeitem" tabindex="-1">Spaghetti</li> 
+          <li id="sweet_dumpling" role="treeitem" tabindex="-1">Sweet Dumpling</li> 
+          <li id="turban" role="treeitem" tabindex="-1">Turban</li> 
+        </ul> 
+      </li> 
+    </ul> 
+  </li> 
+</ul> 
+</div> 
+</body>
+</html>
diff --git a/test/html/iframes-inside-inline-block2.html b/test/html/iframes-inside-inline-block2.html
new file mode 100644
index 0000000..f8efcd9
--- /dev/null
+++ b/test/html/iframes-inside-inline-block2.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+<p>Line 1</p>
+<div style="display: inline-block;">
+<iframe style="margin: 0px; height: 24px;" scrolling="no" frameborder="0" src="abbr.html"></iframe>
+<iframe style="width: 108px; height: 20px;" scrolling="no" frameborder="0"></iframe>
+</div>
+<p>Line 3</p>
+</body>
+</html>
diff --git a/test/html/radio-checked.gif b/test/html/radio-checked.gif
new file mode 100644
index 0000000..dd9b390
Binary files /dev/null and b/test/html/radio-checked.gif differ
diff --git a/test/html/radio-unchecked.gif b/test/html/radio-unchecked.gif
new file mode 100644
index 0000000..9845001
Binary files /dev/null and b/test/html/radio-unchecked.gif differ
diff --git a/test/html/slider_h-focus.png b/test/html/slider_h-focus.png
new file mode 100644
index 0000000..a63fd8c
Binary files /dev/null and b/test/html/slider_h-focus.png differ
diff --git a/test/html/slider_h.png b/test/html/slider_h.png
new file mode 100644
index 0000000..8e85697
Binary files /dev/null and b/test/html/slider_h.png differ
diff --git a/test/html/slider_v-focus.png b/test/html/slider_v-focus.png
new file mode 100644
index 0000000..64752b8
Binary files /dev/null and b/test/html/slider_v-focus.png differ
diff --git a/test/html/slider_v.png b/test/html/slider_v.png
new file mode 100644
index 0000000..91e1333
Binary files /dev/null and b/test/html/slider_v.png differ
diff --git a/test/html/treeContracted.gif b/test/html/treeContracted.gif
new file mode 100644
index 0000000..137fcba
Binary files /dev/null and b/test/html/treeContracted.gif differ
diff --git a/test/html/treeContractedFocus.gif b/test/html/treeContractedFocus.gif
new file mode 100644
index 0000000..5f114cc
Binary files /dev/null and b/test/html/treeContractedFocus.gif differ
diff --git a/test/html/treeExpanded.gif b/test/html/treeExpanded.gif
new file mode 100644
index 0000000..62d3b3c
Binary files /dev/null and b/test/html/treeExpanded.gif differ
diff --git a/test/html/treeExpandedFocus.gif b/test/html/treeExpandedFocus.gif
new file mode 100644
index 0000000..f61a400
Binary files /dev/null and b/test/html/treeExpandedFocus.gif differ
diff --git a/test/keystrokes/firefox/aria_alert_dialog.params 
b/test/keystrokes/firefox/aria_alert_dialog.params
new file mode 100644
index 0000000..caf7d31
--- /dev/null
+++ b/test/keystrokes/firefox/aria_alert_dialog.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-alert-dialog.html
diff --git a/test/keystrokes/firefox/aria_alert_uiuc.py b/test/keystrokes/firefox/aria_alert_dialog.py
similarity index 100%
rename from test/keystrokes/firefox/aria_alert_uiuc.py
rename to test/keystrokes/firefox/aria_alert_dialog.py
diff --git a/test/keystrokes/firefox/aria_button.py b/test/keystrokes/firefox/aria_button.py
index da0538d..29a2786 100644
--- a/test/keystrokes/firefox/aria_button.py
+++ b/test/keystrokes/firefox/aria_button.py
@@ -28,8 +28,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Check Now push button', cursor=1",
      "BRAILLE LINE:  'Browse mode'",
      "     VISIBLE:  'Browse mode', cursor=0",
-     "BRAILLE LINE:  'Check Now push button Check to see if your order has been'",
-     "     VISIBLE:  'Check Now push button Check to s', cursor=1",
      "SPEECH OUTPUT: 'Check Now push button Check to see if your order has been shipped.'",
      "SPEECH OUTPUT: 'Browse mode' voice=system"]))
 
@@ -37,7 +35,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "3. Basic whereamI",
-    ["BRAILLE LINE:  'Check Now push button Check to see if your order has been'",
+    ["BRAILLE LINE:  'Check Now push button'",
+     "     VISIBLE:  'Check Now push button', cursor=1",
+     "BRAILLE LINE:  'Check Now push button Check to see if your order has been'",
      "     VISIBLE:  'Check Now push button Check to s', cursor=1",
      "SPEECH OUTPUT: 'Check Now push button Check to see if your order has been shipped.'"]))
 
diff --git a/test/keystrokes/firefox/aria_button_dojo.py b/test/keystrokes/firefox/aria_button_dojo.py
index 7eba4a3..bb3e512 100644
--- a/test/keystrokes/firefox/aria_button_dojo.py
+++ b/test/keystrokes/firefox/aria_button_dojo.py
@@ -41,17 +41,17 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "5. Tab to first Create button",
-    ["BRAILLE LINE:  'Create push button'",
-     "     VISIBLE:  'Create push button', cursor=1",
-     "SPEECH OUTPUT: 'Create push button'"]))
+    ["BRAILLE LINE:  'Create  push button'",
+     "     VISIBLE:  'Create  push button', cursor=1",
+     "SPEECH OUTPUT: 'Create  push button'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "6. Basic Where Am I on first Create button",
-    ["BRAILLE LINE:  'Create push button'",
-     "     VISIBLE:  'Create push button', cursor=1",
-     "SPEECH OUTPUT: 'Create push button'"]))
+    ["BRAILLE LINE:  'Create  push button'",
+     "     VISIBLE:  'Create  push button', cursor=1",
+     "SPEECH OUTPUT: 'Create  push button'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
@@ -65,15 +65,15 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "8. Tab to second Create button",
-    ["BRAILLE LINE:  'Create push button'",
-     "     VISIBLE:  'Create push button', cursor=1",
-     "SPEECH OUTPUT: 'Create push button creative title'"]))
+    ["BRAILLE LINE:  'Create  push button'",
+     "     VISIBLE:  'Create  push button', cursor=1",
+     "SPEECH OUTPUT: 'Create  push button creative title'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "9. Tab to drop down menu on Create -- whose tooltip and accessible name is 'save options'",
-    ["BRAILLE LINE:  '<button> push button <input type='button'> push button Create View save options push 
button Edit! Color'",
+    ["BRAILLE LINE:  '<button> push button <input type='button'> push button Create View Create save options 
push button Edit! Color'",
      "     VISIBLE:  'save options push button Edit! C', cursor=1",
      "SPEECH OUTPUT: 'save options push button'"]))
 
@@ -81,7 +81,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
 sequence.append(utils.AssertPresentationAction(
     "10. Open drop down menu on Create",
-    ["BRAILLE LINE:  '<button> push button <input type='button'> push button Create View save options push 
button Edit! Color'",
+    ["BRAILLE LINE:  '<button> push button <input type='button'> push button Create View Create save options 
push button Edit! Color'",
      "     VISIBLE:  'save options push button Edit! C', cursor=1",
      "BRAILLE LINE:  'Create blank'",
      "     VISIBLE:  'Create blank', cursor=1",
@@ -112,21 +112,21 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "13. Go to Edit!",
-    ["BRAILLE LINE:  'Edit! push button'",
-     "     VISIBLE:  'Edit! push button', cursor=1",
+    ["BRAILLE LINE:  'Edit!  push button'",
+     "     VISIBLE:  'Edit!  push button', cursor=1",
      "BRAILLE LINE:  'Browse mode'",
      "     VISIBLE:  'Browse mode', cursor=0",
-     "SPEECH OUTPUT: 'Edit! push button edit title'",
+     "SPEECH OUTPUT: 'Edit!  push button edit title'",
      "SPEECH OUTPUT: 'Browse mode' voice=system"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("space"))
 sequence.append(utils.AssertPresentationAction(
     "14. Open the Edit! menu",
-    ["BRAILLE LINE:  'Edit! push button'",
-     "     VISIBLE:  'Edit! push button', cursor=1",
-     "BRAILLE LINE:  'Edit! push button'",
-     "     VISIBLE:  'Edit! push button', cursor=1",
+    ["BRAILLE LINE:  'Edit!  push button'",
+     "     VISIBLE:  'Edit!  push button', cursor=1",
+     "BRAILLE LINE:  'Edit!  push button'",
+     "     VISIBLE:  'Edit!  push button', cursor=1",
      "BRAILLE LINE:  'Cut'",
      "     VISIBLE:  'Cut', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
@@ -192,40 +192,36 @@ sequence.append(utils.AssertPresentationAction(
     "21. Close the Submenu",
     ["BRAILLE LINE:  'Submenu menu'",
      "     VISIBLE:  'Submenu menu', cursor=1",
-     "SPEECH OUTPUT: 'Edit! edit title panel'",
      "SPEECH OUTPUT: 'Edit! menu'",
-     "SPEECH OUTPUT: 'Submenu menu'",
-     "SPEECH OUTPUT: 'Focus mode' voice=system"]))
+     "SPEECH OUTPUT: 'Submenu menu'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Escape"))
 sequence.append(utils.AssertPresentationAction(
     "22. Close the Edit! menu",
-    ["BRAILLE LINE:  'Submenu Submenu menu'",
-     "     VISIBLE:  'Submenu Submenu menu', cursor=9",
-     "BRAILLE LINE:  'Edit! collapsed push button'",
-     "     VISIBLE:  'Edit! collapsed push button', cursor=1",
-     "SPEECH OUTPUT: 'Edit! collapsed push button edit title'"]))
+    ["BRAILLE LINE:  'Edit!  collapsed push button'",
+     "     VISIBLE:  'Edit!  collapsed push button', cursor=1",
+     "SPEECH OUTPUT: 'Edit!  collapsed push button edit title'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "23. Tab to the Color button",
-    ["BRAILLE LINE:  'Color push button'",
-     "     VISIBLE:  'Color push button', cursor=1",
+    ["BRAILLE LINE:  'Color  push button'",
+     "     VISIBLE:  'Color  push button', cursor=1",
      "BRAILLE LINE:  'Browse mode'",
      "     VISIBLE:  'Browse mode', cursor=0",
-     "SPEECH OUTPUT: 'Color push button'",
+     "SPEECH OUTPUT: 'Color  push button'",
      "SPEECH OUTPUT: 'Browse mode' voice=system"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("space"))
 sequence.append(utils.AssertPresentationAction(
     "24. Open the Color menu",
-    ["BRAILLE LINE:  'Color push button'",
-     "     VISIBLE:  'Color push button', cursor=1",
-     "BRAILLE LINE:  'Color push button'",
-     "     VISIBLE:  'Color push button', cursor=1",
+    ["BRAILLE LINE:  'Color  push button'",
+     "     VISIBLE:  'Color  push button', cursor=1",
+     "BRAILLE LINE:  'Color  push button'",
+     "     VISIBLE:  'Color  push button', cursor=1",
      "BRAILLE LINE:  'white table cell'",
      "     VISIBLE:  'white table cell', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
@@ -247,9 +243,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Escape"))
 sequence.append(utils.AssertPresentationAction(
     "26. Close the Color menu",
-    ["BRAILLE LINE:  'Color collapsed push button'",
-     "     VISIBLE:  'Color collapsed push button', cursor=1",
-     "SPEECH OUTPUT: 'Color collapsed push button'"]))
+    ["BRAILLE LINE:  'Color  collapsed push button'",
+     "     VISIBLE:  'Color  collapsed push button', cursor=1",
+     "SPEECH OUTPUT: 'Color  collapsed push button'"]))
 
 for i in range(18):
     sequence.append(KeyComboAction("Tab"))
@@ -258,21 +254,16 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "27. Tab to the toggle me off button",
-    ["BRAILLE LINE:  '&=y Toggle me off toggle button'",
-     "     VISIBLE:  '&=y Toggle me off toggle button', cursor=1",
-     "SPEECH OUTPUT: 'Toggle me off toggle button pressed'"]))
+    ["BRAILLE LINE:  '&=y Toggle me off  toggle button'",
+     "     VISIBLE:  '&=y Toggle me off  toggle button', cursor=1",
+     "SPEECH OUTPUT: 'Toggle me off  toggle button pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("space"))
 sequence.append(utils.AssertPresentationAction(
     "28. Toggle the state of the toggle me off button",
-    ["KNOWN ISSUE: This seems an excessive amount of braille updating",
-     "BRAILLE LINE:  '& y toggle me on toggle button'",
+    ["BRAILLE LINE:  '& y toggle me on toggle button'",
      "     VISIBLE:  '& y toggle me on toggle button', cursor=1",
-     "BRAILLE LINE:  'toggle me on $l'",
-     "     VISIBLE:  'toggle me on $l', cursor=1",
-     "BRAILLE LINE:  'toggle me on $l'",
-     "     VISIBLE:  'toggle me on $l', cursor=1",
      "SPEECH OUTPUT: 'not pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -281,35 +272,31 @@ sequence.append(utils.AssertPresentationAction(
     "29. Toggle the state of the toggle me off button",
     ["BRAILLE LINE:  '&=y toggle me off toggle button'",
      "     VISIBLE:  '&=y toggle me off toggle button', cursor=1",
-     "BRAILLE LINE:  'toggle me off $l'",
-     "     VISIBLE:  'toggle me off $l', cursor=1",
-     "BRAILLE LINE:  'toggle me off $l'",
-     "     VISIBLE:  'toggle me off $l', cursor=1",
      "SPEECH OUTPUT: 'pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "30. Tab to the toggle me button",
-    ["BRAILLE LINE:  'Toggle me push button'",
-     "     VISIBLE:  'Toggle me push button', cursor=1",
-     "SPEECH OUTPUT: 'Toggle me push button'"]))
+    ["BRAILLE LINE:  'Toggle me  push button'",
+     "     VISIBLE:  'Toggle me  push button', cursor=1",
+     "SPEECH OUTPUT: 'Toggle me  push button'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("space"))
 sequence.append(utils.AssertPresentationAction(
     "31. Toggle the state of the toggle me button",
-    ["KNOWN ISSUE: We seem to be missing the expected events and state changes. Dojo bug?",
-     "BRAILLE LINE:  'Toggle me push button'",
-     "     VISIBLE:  'Toggle me push button', cursor=1"]))
+    ["KNOWN ISSUE: This claims to be a toggle button in name; in role it's a push button. We don't announce 
pressing buttons.",
+     "BRAILLE LINE:  'Toggle me  push button'",
+     "     VISIBLE:  'Toggle me  push button', cursor=1"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("space"))
 sequence.append(utils.AssertPresentationAction(
     "32. Toggle the state of the toggle me button",
-    ["KNOWN ISSUE: We seem to be missing the expected events and state changes. Dojo bug?",
-     "BRAILLE LINE:  'Toggle me push button'",
-     "     VISIBLE:  'Toggle me push button', cursor=1"]))
+    ["KNOWN ISSUE: This claims to be a toggle button in name; in role it's a push button. We don't announce 
pressing buttons.",
+     "BRAILLE LINE:  'Toggle me  push button'",
+     "     VISIBLE:  'Toggle me  push button', cursor=1"]))
 
 sequence.append(utils.AssertionSummaryAction())
 sequence.start()
diff --git a/test/keystrokes/firefox/aria_button_toggle.params 
b/test/keystrokes/firefox/aria_button_toggle.params
new file mode 100644
index 0000000..331ff1b
--- /dev/null
+++ b/test/keystrokes/firefox/aria_button_toggle.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-button-toggle.html
\ No newline at end of file
diff --git a/test/keystrokes/firefox/aria_button_uiuc.py b/test/keystrokes/firefox/aria_button_toggle.py
similarity index 71%
rename from test/keystrokes/firefox/aria_button_uiuc.py
rename to test/keystrokes/firefox/aria_button_toggle.py
index b04ba0f..a0bbfcb 100644
--- a/test/keystrokes/firefox/aria_button_uiuc.py
+++ b/test/keystrokes/firefox/aria_button_toggle.py
@@ -1,15 +1,13 @@
 #!/usr/bin/python
 
-"""Test of UIUC button presentation."""
-
 from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
 
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
@@ -17,9 +15,7 @@ sequence.append(utils.AssertPresentationAction(
     "1. Tab to first button",
     ["BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
      "     VISIBLE:  '& y Font Larger toggle button & ', cursor=1",
-     "BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
-     "     VISIBLE:  '& y Font Larger toggle button & ', cursor=1",
-     "SPEECH OUTPUT: 'Font Larger toggle button not pressed'"]))
+     "SPEECH OUTPUT: 'Font Larger + toggle button not pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
@@ -27,7 +23,7 @@ sequence.append(utils.AssertPresentationAction(
     "2. Basic whereamI",
     ["BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
      "     VISIBLE:  '& y Font Larger toggle button & ', cursor=1",
-     "SPEECH OUTPUT: 'Font Larger toggle button not pressed'"]))
+     "SPEECH OUTPUT: 'Font Larger + toggle button not pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
@@ -35,15 +31,13 @@ sequence.append(utils.AssertPresentationAction(
     "3. Tab to second button",
     ["BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
      "     VISIBLE:  '& y Font Smaller toggle button &', cursor=1",
-     "BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
-     "     VISIBLE:  '& y Font Smaller toggle button &', cursor=1",
-     "SPEECH OUTPUT: 'Font Smaller toggle button not pressed'"]))
+     "SPEECH OUTPUT: 'Font Smaller - toggle button not pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
 sequence.append(utils.AssertPresentationAction(
     "4. Push second button",
-    ["KNOWN ISSUE: We are presenting nothing here for some reason. Missing event?",
+    ["KNOWN ISSUE: We're presenting nothing here.",
      ""]))
 
 sequence.append(utils.StartRecordingAction())
@@ -52,9 +46,7 @@ sequence.append(utils.AssertPresentationAction(
     "5. Tab to third button",
     ["BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
      "     VISIBLE:  '&=y Italic toggle button & y Bol', cursor=1",
-     "BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button &=y Italic toggle button 
& y Bold toggle button'",
-     "     VISIBLE:  '&=y Italic toggle button & y Bol', cursor=1",
-     "SPEECH OUTPUT: 'Italic toggle button pressed'"]))
+     "SPEECH OUTPUT: 'Italic i toggle button pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
@@ -70,9 +62,7 @@ sequence.append(utils.AssertPresentationAction(
     "7. Tab to fourth button",
     ["BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button & y Italic toggle button 
& y Bold toggle button'",
      "     VISIBLE:  '& y Bold toggle button', cursor=1",
-     "BRAILLE LINE:  '& y Font Larger toggle button & y Font Smaller toggle button & y Italic toggle button 
& y Bold toggle button'",
-     "     VISIBLE:  '& y Bold toggle button', cursor=1",
-     "SPEECH OUTPUT: 'Bold toggle button not pressed'"]))
+     "SPEECH OUTPUT: 'Bold B toggle button not pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
diff --git a/test/keystrokes/firefox/aria_checkbox.py b/test/keystrokes/firefox/aria_checkbox.py
index 65685e4..4150a8a 100644
--- a/test/keystrokes/firefox/aria_checkbox.py
+++ b/test/keystrokes/firefox/aria_checkbox.py
@@ -13,8 +13,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Tab to first checkbox",
     ["BRAILLE LINE:  '<x> Include decorative fruit basket check box'",
      "     VISIBLE:  '<x> Include decorative fruit bas', cursor=1",
-     "BRAILLE LINE:  '<x> Include decorative fruit basket check box'",
-     "     VISIBLE:  '<x> Include decorative fruit bas', cursor=1",
      "SPEECH OUTPUT: 'Include decorative fruit basket check box checked'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -31,8 +29,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Tab to second checkbox",
     ["BRAILLE LINE:  '<x> Invalid checkbox check box'",
      "     VISIBLE:  '<x> Invalid checkbox check box', cursor=1",
-     "BRAILLE LINE:  '<x> Invalid checkbox check box'",
-     "     VISIBLE:  '<x> Invalid checkbox check box', cursor=1",
      "SPEECH OUTPUT: 'Invalid checkbox check box checked'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -49,8 +45,6 @@ sequence.append(utils.AssertPresentationAction(
     "5. Tab to third checkbox",
     ["BRAILLE LINE:  '<x> Required checkbox check box'",
      "     VISIBLE:  '<x> Required checkbox check box', cursor=1",
-     "BRAILLE LINE:  '<x> Required checkbox check box'",
-     "     VISIBLE:  '<x> Required checkbox check box', cursor=1",
      "SPEECH OUTPUT: 'Required checkbox check box checked required'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -83,8 +77,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Tab to checkbox tristate",
     ["BRAILLE LINE:  '<x> Tri-state checkbox check box'",
      "     VISIBLE:  '<x> Tri-state checkbox check box', cursor=1",
-     "BRAILLE LINE:  '<x> Tri-state checkbox check box'",
-     "     VISIBLE:  '<x> Tri-state checkbox check box', cursor=1",
      "SPEECH OUTPUT: 'Tri-state checkbox check box checked required'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/aria_combobox_dojo.py b/test/keystrokes/firefox/aria_combobox_dojo.py
index 3d566e8..3ed7ba7 100644
--- a/test/keystrokes/firefox/aria_combobox_dojo.py
+++ b/test/keystrokes/firefox/aria_combobox_dojo.py
@@ -31,8 +31,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Replace existing text with a 'C'",
     ["BRAILLE LINE:  'US State test 1 (200% Courier font): C $l'",
      "     VISIBLE:  '(200% Courier font): C $l', cursor=23",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): C $l'",
-     "     VISIBLE:  '(200% Courier font): C $l', cursor=23",
      "BRAILLE LINE:  'US State test 1 (200% Courier font):'",
      "     VISIBLE:  'US State test 1 (200% Courier fo', cursor=1",
      "SPEECH OUTPUT: 'expanded'"]))
@@ -41,86 +39,67 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "3. Down Arrow",
-    ["KNOWN ISSUE: Too much braille updating",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): California $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): California $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "BRAILLE LINE:  'California (CA)'",
-     "     VISIBLE:  'California (CA)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): California $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'California'",
-     "SPEECH OUTPUT: 'California List with 3 items'",
-     "SPEECH OUTPUT: 'California (CA)'"]))
+    ["BRAILLE LINE:  'C alifornia (CA)'",
+     "     VISIBLE:  'C alifornia (CA)', cursor=1",
+     "SPEECH OUTPUT: 'California menu'",
+     "SPEECH OUTPUT: 'C alifornia (CA)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "4. Down Arrow",
-    ["BRAILLE LINE:  'Colorado (CO)'",
-     "     VISIBLE:  'Colorado (CO)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): Colorado $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'Colorado (CO)'"]))
+    ["BRAILLE LINE:  'C olorado (CO)'",
+     "     VISIBLE:  'C olorado (CO)', cursor=1",
+     "SPEECH OUTPUT: 'C olorado (CO)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "5. Down Arrow",
-    ["BRAILLE LINE:  'Connecticut (CT)'",
-     "     VISIBLE:  'Connecticut (CT)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): Connecticut $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'Connecticut (CT)'"]))
+    ["BRAILLE LINE:  'C onnecticut (CT)'",
+     "     VISIBLE:  'C onnecticut (CT)', cursor=1",
+     "SPEECH OUTPUT: 'C onnecticut (CT)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "6. Down Arrow",
-    ["BRAILLE LINE:  'California (CA)'",
-     "     VISIBLE:  'California (CA)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): California $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'California (CA)'"]))
+    ["BRAILLE LINE:  'C alifornia (CA)'",
+     "     VISIBLE:  'C alifornia (CA)', cursor=1",
+     "SPEECH OUTPUT: 'C alifornia (CA)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "7. Up Arrow",
-    ["BRAILLE LINE:  'Connecticut (CT)'",
-     "     VISIBLE:  'Connecticut (CT)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): Connecticut $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'Connecticut (CT)'"]))
+    ["BRAILLE LINE:  'C onnecticut (CT)'",
+     "     VISIBLE:  'C onnecticut (CT)', cursor=1",
+     "SPEECH OUTPUT: 'C onnecticut (CT)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "8. Up Arrow",
-    ["BRAILLE LINE:  'Colorado (CO)'",
-     "     VISIBLE:  'Colorado (CO)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): Colorado $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'Colorado (CO)'"]))
+    ["BRAILLE LINE:  'C olorado (CO)'",
+     "     VISIBLE:  'C olorado (CO)', cursor=1",
+     "SPEECH OUTPUT: 'C olorado (CO)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "9. Up Arrow",
-    ["BRAILLE LINE:  'California (CA)'",
-     "     VISIBLE:  'California (CA)', cursor=1",
-     "BRAILLE LINE:  'US State test 1 (200% Courier font): California $l'",
-     "     VISIBLE:  'ate test 1 (200% Courier font): ', cursor=32",
-     "SPEECH OUTPUT: 'California (CA)'"]))
+    ["BRAILLE LINE:  'C alifornia (CA)'",
+     "     VISIBLE:  'C alifornia (CA)', cursor=1",
+     "SPEECH OUTPUT: 'C alifornia (CA)'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "10. Basic Where Am I - Combo box expanded",
-    ["BRAILLE LINE:  'California (CA)'",
-     "     VISIBLE:  'California (CA)', cursor=1",
-     "SPEECH OUTPUT: 'list item California (CA) 1 of 3'"]))
+    ["BRAILLE LINE:  'C alifornia (CA)'",
+     "     VISIBLE:  'C alifornia (CA)', cursor=1",
+     "SPEECH OUTPUT: 'California menu'",
+     "SPEECH OUTPUT: 'panel C alifornia (CA) 1 of 3'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Escape"))
diff --git a/test/keystrokes/firefox/aria_landmarks.py b/test/keystrokes/firefox/aria_landmarks.py
index 41949f1..01d8d47 100644
--- a/test/keystrokes/firefox/aria_landmarks.py
+++ b/test/keystrokes/firefox/aria_landmarks.py
@@ -15,7 +15,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. m to next landmark",
     ["BRAILLE LINE:  'navigation main'",
      "     VISIBLE:  'navigation main', cursor=1",
-     "SPEECH OUTPUT: 'navigation'"]))
+     "SPEECH OUTPUT: 'navigation'",
+     "SPEECH OUTPUT: 'main'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
@@ -23,16 +24,16 @@ sequence.append(utils.AssertPresentationAction(
     "2. m to next landmark",
     ["BRAILLE LINE:  'navigation main'",
      "     VISIBLE:  'navigation main', cursor=12",
-     "SPEECH OUTPUT: 'main'",
-     "SPEECH OUTPUT: 'Firefox'"]))
+     "SPEECH OUTPUT: 'navigation'",
+     "SPEECH OUTPUT: 'main'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
 sequence.append(utils.AssertPresentationAction(
     "3. m to next landmark",
-    ["BRAILLE LINE:  'application'",
-     "     VISIBLE:  'application', cursor=1",
-     "SPEECH OUTPUT: 'Firefox'"]))
+    ["BRAILLE LINE:  'application embedded'",
+     "     VISIBLE:  'application embedded', cursor=1",
+     "SPEECH OUTPUT: 'application embedded'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
@@ -40,14 +41,20 @@ sequence.append(utils.AssertPresentationAction(
     "4. m to next landmark",
     ["BRAILLE LINE:  'complementary'",
      "     VISIBLE:  'complementary', cursor=1",
-     "SPEECH OUTPUT: 'complementary'",
-     "SPEECH OUTPUT: 'form'",
-     "SPEECH OUTPUT: 'search'"]))
+     "SPEECH OUTPUT: 'complementary'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
 sequence.append(utils.AssertPresentationAction(
     "5. m to next landmark",
+    ["BRAILLE LINE:  'form'",
+     "     VISIBLE:  'form', cursor=1",
+     "SPEECH OUTPUT: 'form'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("m"))
+sequence.append(utils.AssertPresentationAction(
+    "6. m to next landmark",
     ["BRAILLE LINE:  'search'",
      "     VISIBLE:  'search', cursor=1",
      "SPEECH OUTPUT: 'search'"]))
@@ -55,7 +62,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
 sequence.append(utils.AssertPresentationAction(
-    "6. m to next landmark",
+    "7. m to next landmark",
     ["BRAILLE LINE:  'contentinfo'",
      "     VISIBLE:  'contentinfo', cursor=1",
      "SPEECH OUTPUT: 'contentinfo'"]))
@@ -63,7 +70,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("m"))
 sequence.append(utils.AssertPresentationAction(
-    "7. m to next landmark",
+    "8. m to next landmark",
     ["BRAILLE LINE:  'Wrapping to top.'",
      "     VISIBLE:  'Wrapping to top.', cursor=0",
      "BRAILLE LINE:  'banner'",
@@ -74,7 +81,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>m"))
 sequence.append(utils.AssertPresentationAction(
-    "8. Shift+m to previous landmark",
+    "9. Shift+m to previous landmark",
     ["BRAILLE LINE:  'Wrapping to bottom.'",
      "     VISIBLE:  'Wrapping to bottom.', cursor=0",
      "BRAILLE LINE:  'contentinfo'",
@@ -85,7 +92,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>m"))
 sequence.append(utils.AssertPresentationAction(
-    "9. Shift+m to previous landmark",
+    "10. Shift+m to previous landmark",
     ["BRAILLE LINE:  'search'",
      "     VISIBLE:  'search', cursor=1",
      "SPEECH OUTPUT: 'search'"]))
@@ -93,25 +100,26 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>m"))
 sequence.append(utils.AssertPresentationAction(
-    "10. Shift+m to previous landmark",
+    "11. Shift+m to previous landmark",
     ["KNOWN ISSUE: We are skipping over complementary on the way back",
-     "BRAILLE LINE:  'application'",
-     "     VISIBLE:  'application', cursor=1",
-     "SPEECH OUTPUT: 'Firefox'"]))
+     "BRAILLE LINE:  'application embedded'",
+     "     VISIBLE:  'application embedded', cursor=1",
+     "SPEECH OUTPUT: 'application embedded'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>m"))
 sequence.append(utils.AssertPresentationAction(
-    "11. Shift+m to previous landmark",
+    "12. Shift+m to previous landmark",
     ["KNOWN ISSUE: We are skipping over navigation on the way back",
      "BRAILLE LINE:  'navigation main'",
      "     VISIBLE:  'navigation main', cursor=1",
-     "SPEECH OUTPUT: 'navigation'"]))
+     "SPEECH OUTPUT: 'navigation'",
+     "SPEECH OUTPUT: 'main'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>m"))
 sequence.append(utils.AssertPresentationAction(
-    "12. Shift+m to previous landmark",
+    "13. Shift+m to previous landmark",
     ["BRAILLE LINE:  'banner'",
      "     VISIBLE:  'banner', cursor=1",
      "SPEECH OUTPUT: 'banner'"]))
diff --git a/test/keystrokes/firefox/aria_menu.py b/test/keystrokes/firefox/aria_menu.py
index 8b0785a..fdf3409 100644
--- a/test/keystrokes/firefox/aria_menu.py
+++ b/test/keystrokes/firefox/aria_menu.py
@@ -7,14 +7,16 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control><Alt>m"))
 sequence.append(utils.AssertPresentationAction(
     "1. Move to the menu",
-    ["BRAILLE LINE:  'Entry # column header'",
-     "     VISIBLE:  'Entry # column header', cursor=1",
-     "BRAILLE LINE:  'Edit menu'",
-     "     VISIBLE:  'Edit menu', cursor=1",
+    ["BRAILLE LINE:  'table'",
+     "     VISIBLE:  'table', cursor=1",
      "BRAILLE LINE:  'Edit menu'",
      "     VISIBLE:  'Edit menu', cursor=1",
      "SPEECH OUTPUT: 'Edit menu'"]))
@@ -34,8 +36,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Move to View",
     ["BRAILLE LINE:  'View menu'",
      "     VISIBLE:  'View menu', cursor=1",
-     "BRAILLE LINE:  'View menu'",
-     "     VISIBLE:  'View menu', cursor=1",
      "SPEECH OUTPUT: 'View menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -44,8 +44,6 @@ sequence.append(utils.AssertPresentationAction(
     "4. Move to Themes",
     ["BRAILLE LINE:  'Themes          > menu'",
      "     VISIBLE:  'Themes          > menu', cursor=1",
-     "BRAILLE LINE:  'Themes          > menu'",
-     "     VISIBLE:  'Themes          > menu', cursor=1",
      "SPEECH OUTPUT: 'Themes          > menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -54,8 +52,6 @@ sequence.append(utils.AssertPresentationAction(
     "5. Move to basic grey",
     ["BRAILLE LINE:  'Basic Grey'",
      "     VISIBLE:  'Basic Grey', cursor=1",
-     "BRAILLE LINE:  'Basic Grey'",
-     "     VISIBLE:  'Basic Grey', cursor=1",
      "SPEECH OUTPUT: 'Basic Grey'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -64,8 +60,6 @@ sequence.append(utils.AssertPresentationAction(
     "6. Move to the blues",
     ["BRAILLE LINE:  'The Blues'",
      "     VISIBLE:  'The Blues', cursor=1",
-     "BRAILLE LINE:  'The Blues'",
-     "     VISIBLE:  'The Blues', cursor=1",
      "SPEECH OUTPUT: 'The Blues'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -74,8 +68,6 @@ sequence.append(utils.AssertPresentationAction(
     "7. Move to garden",
     ["BRAILLE LINE:  'Garden'",
      "     VISIBLE:  'Garden', cursor=1",
-     "BRAILLE LINE:  'Garden'",
-     "     VISIBLE:  'Garden', cursor=1",
      "SPEECH OUTPUT: 'Garden'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -84,8 +76,6 @@ sequence.append(utils.AssertPresentationAction(
     "8. Move to in the pink",
     ["BRAILLE LINE:  'In the Pink grayed'",
      "     VISIBLE:  'In the Pink grayed', cursor=1",
-     "BRAILLE LINE:  'In the Pink grayed'",
-     "     VISIBLE:  'In the Pink grayed', cursor=1",
      "SPEECH OUTPUT: 'In the Pink grayed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -94,8 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Move to rose",
     ["BRAILLE LINE:  'Rose'",
      "     VISIBLE:  'Rose', cursor=1",
-     "BRAILLE LINE:  'Rose'",
-     "     VISIBLE:  'Rose', cursor=1",
      "SPEECH OUTPUT: 'Rose'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -104,8 +92,6 @@ sequence.append(utils.AssertPresentationAction(
     "10. Move back to Themes",
     ["BRAILLE LINE:  'Themes          > menu'",
      "     VISIBLE:  'Themes          > menu', cursor=1",
-     "BRAILLE LINE:  'Themes          > menu'",
-     "     VISIBLE:  'Themes          > menu', cursor=1",
      "SPEECH OUTPUT: 'Themes          > menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -114,8 +100,6 @@ sequence.append(utils.AssertPresentationAction(
     "11. Move to hide",
     ["BRAILLE LINE:  'Hide'",
      "     VISIBLE:  'Hide', cursor=1",
-     "BRAILLE LINE:  'Hide'",
-     "     VISIBLE:  'Hide', cursor=1",
      "SPEECH OUTPUT: 'Hide'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -124,8 +108,6 @@ sequence.append(utils.AssertPresentationAction(
     "12. Move to show",
     ["BRAILLE LINE:  'Show'",
      "     VISIBLE:  'Show', cursor=1",
-     "BRAILLE LINE:  'Show'",
-     "     VISIBLE:  'Show', cursor=1",
      "SPEECH OUTPUT: 'Show'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -134,8 +116,6 @@ sequence.append(utils.AssertPresentationAction(
     "13. Move to more",
     ["BRAILLE LINE:  'More                > menu'",
      "     VISIBLE:  'More                > menu', cursor=1",
-     "BRAILLE LINE:  'More                > menu'",
-     "     VISIBLE:  'More                > menu', cursor=1",
      "SPEECH OUTPUT: 'More                > menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -144,8 +124,6 @@ sequence.append(utils.AssertPresentationAction(
     "14. Move to one",
     ["BRAILLE LINE:  'one'",
      "     VISIBLE:  'one', cursor=1",
-     "BRAILLE LINE:  'one'",
-     "     VISIBLE:  'one', cursor=1",
      "SPEECH OUTPUT: 'one'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -154,8 +132,6 @@ sequence.append(utils.AssertPresentationAction(
     "15. Move to two",
     ["BRAILLE LINE:  'two'",
      "     VISIBLE:  'two', cursor=1",
-     "BRAILLE LINE:  'two'",
-     "     VISIBLE:  'two', cursor=1",
      "SPEECH OUTPUT: 'two'"]))
 
 sequence.append(KeyComboAction("Escape"))
diff --git a/test/keystrokes/firefox/aria_radiobutton.params b/test/keystrokes/firefox/aria_radiobutton.params
new file mode 100644
index 0000000..f843d49
--- /dev/null
+++ b/test/keystrokes/firefox/aria_radiobutton.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-radiobutton.html
\ No newline at end of file
diff --git a/test/keystrokes/firefox/aria_radio_button_uiuc.py b/test/keystrokes/firefox/aria_radiobutton.py
similarity index 64%
rename from test/keystrokes/firefox/aria_radio_button_uiuc.py
rename to test/keystrokes/firefox/aria_radiobutton.py
index b26cd53..7d56a26 100644
--- a/test/keystrokes/firefox/aria_radio_button_uiuc.py
+++ b/test/keystrokes/firefox/aria_radiobutton.py
@@ -1,25 +1,16 @@
 #!/usr/bin/python
 
-"""Test of UIUC radio button presentation."""
-
 from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
 
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "1. Tab to first radio button",
     ["BRAILLE LINE:  '&=y Radio Maria radio button'",
      "     VISIBLE:  '&=y Radio Maria radio button', cursor=1",
-     "BRAILLE LINE:  '&=y Radio Maria radio button'",
-     "     VISIBLE:  '&=y Radio Maria radio button', cursor=1",
      "SPEECH OUTPUT: 'Lunch Options panel'",
      "SPEECH OUTPUT: 'Radio Maria selected radio button'"]))
 
@@ -35,10 +26,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "3. Move to next radio button",
-    ["KNOWN ISSUE: It looks like at the time we move to it, the state hasn't changed yet. This is something 
better handled by focus mode but users don't want that.",
-     "BRAILLE LINE:  '& y Rainbow Gardens radio button'",
-     "     VISIBLE:  '& y Rainbow Gardens radio button', cursor=1",
-     "SPEECH OUTPUT: 'Rainbow Gardens not selected radio button'"]))
+    ["BRAILLE LINE:  '&=y Rainbow Gardens radio button'",
+     "     VISIBLE:  '&=y Rainbow Gardens radio button', cursor=1",
+     "SPEECH OUTPUT: 'Rainbow Gardens selected radio button'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
@@ -62,8 +52,6 @@ sequence.append(utils.AssertPresentationAction(
     "6. Tab to second radio group",
     ["BRAILLE LINE:  '&=y Water radio button'",
      "     VISIBLE:  '&=y Water radio button', cursor=1",
-     "BRAILLE LINE:  '&=y Water radio button'",
-     "     VISIBLE:  '&=y Water radio button', cursor=1",
      "SPEECH OUTPUT: 'Drink Options panel'",
      "SPEECH OUTPUT: 'Water selected radio button'"]))
 
@@ -71,19 +59,17 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "7. Move to next radio button",
-    ["KNOWN ISSUE: It looks like at the time we move to it, the state hasn't changed yet. This is something 
better handled by focus mode but users don't want that.",
-     "BRAILLE LINE:  '& y Tea radio button'",
-     "     VISIBLE:  '& y Tea radio button', cursor=1",
-     "SPEECH OUTPUT: 'Tea not selected radio button'"]))
+    ["BRAILLE LINE:  '&=y Tea radio button'",
+     "     VISIBLE:  '&=y Tea radio button', cursor=1",
+     "SPEECH OUTPUT: 'Tea selected radio button'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "8. Move back to previous radio button",
-    ["KNOWN ISSUE: It looks like at the time we move to it, the state hasn't changed yet. This is something 
better handled by focus mode but users don't want that.",
-     "BRAILLE LINE:  '& y Water radio button'",
-     "     VISIBLE:  '& y Water radio button', cursor=1",
-     "SPEECH OUTPUT: 'Water not selected radio button'"]))
+    ["BRAILLE LINE:  '&=y Water radio button'",
+     "     VISIBLE:  '&=y Water radio button', cursor=1",
+     "SPEECH OUTPUT: 'Water selected radio button'"]))
 
 sequence.append(utils.AssertionSummaryAction())
 sequence.start()
diff --git a/test/keystrokes/firefox/aria_slider_dojo.py b/test/keystrokes/firefox/aria_slider_dojo.py
index 00245f8..895669a 100644
--- a/test/keystrokes/firefox/aria_slider_dojo.py
+++ b/test/keystrokes/firefox/aria_slider_dojo.py
@@ -11,8 +11,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "1. Tab to first slider",
-    ["KNOWN ISSUE: Why are we not displaying the value after focus mode?",
-     "BRAILLE LINE:  'slider 1 10 slider'",
+    ["BRAILLE LINE:  'slider 1 10 slider'",
      "     VISIBLE:  'slider 1 10 slider', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
      "     VISIBLE:  'Focus mode', cursor=0",
@@ -26,33 +25,33 @@ sequence.append(utils.AssertPresentationAction(
     ["KNOWN ISSUE: This is the value exposed to us so we're passing it along as-is.",
      "BRAILLE LINE:  'slider 1 10 slider'",
      "     VISIBLE:  'slider 1 10 slider', cursor=1",
-     "BRAILLE LINE:  'slider 1 10.238095238095237 slider'",
-     "     VISIBLE:  'slider 1 10.238095238095237 slid', cursor=1",
-     "SPEECH OUTPUT: '10.238095238095237'"]))
+     "BRAILLE LINE:  'slider 1 10.2[0-9]+ slider'",
+     "     VISIBLE:  'slider 1 10.2[0-9]+ slid', cursor=1",
+     "SPEECH OUTPUT: '10.2[0-9]+'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
 sequence.append(utils.AssertPresentationAction(
     "3. Increment first slider",
-    ["BRAILLE LINE:  'slider 1 10.476190476190476 slider'",
-     "     VISIBLE:  'slider 1 10.476190476190476 slid', cursor=1",
-     "SPEECH OUTPUT: '10.476190476190476'"]))
+    ["BRAILLE LINE:  'slider 1 10.(4|5)[0-9]+ slider'",
+     "     VISIBLE:  'slider 1 10.(4|5)[0-9]+ slid', cursor=1",
+     "SPEECH OUTPUT: '10.(4|5)[0-9]+'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
 sequence.append(utils.AssertPresentationAction(
     "4. Decrement first slider",
-    ["BRAILLE LINE:  'slider 1 10.238095238095237 slider'",
-     "     VISIBLE:  'slider 1 10.238095238095237 slid', cursor=1",
-     "SPEECH OUTPUT: '10.238095238095237'"]))
+    ["BRAILLE LINE:  'slider 1 10.2[0-9]+ slider'",
+     "     VISIBLE:  'slider 1 10.2[0-9]+ slid', cursor=1",
+     "SPEECH OUTPUT: '10.2[0-9]+'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
 sequence.append(utils.AssertPresentationAction(
     "5. Decrement first slider",
-    ["BRAILLE LINE:  'slider 1 10 slider'",
-     "     VISIBLE:  'slider 1 10 slider', cursor=1",
-     "SPEECH OUTPUT: '10'"]))
+    ["BRAILLE LINE:  'slider 1 10.0[0-9]+ slider'",
+     "     VISIBLE:  'slider 1 10.0[0-9]+ slid', cursor=1",
+     "SPEECH OUTPUT: '10.0[0-9]+'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
diff --git a/test/keystrokes/firefox/aria_slider_tpg.py b/test/keystrokes/firefox/aria_slider_tpg.py
index e565d9e..9acca7e 100644
--- a/test/keystrokes/firefox/aria_slider_tpg.py
+++ b/test/keystrokes/firefox/aria_slider_tpg.py
@@ -24,10 +24,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Volume Right Arrow",
     ["BRAILLE LINE:  'Volume 1 % slider'",
      "     VISIBLE:  'Volume 1 % slider', cursor=1",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
      "SPEECH OUTPUT: '1 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -36,10 +32,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Volume Right Arrow",
     ["BRAILLE LINE:  'Volume 2 % slider'",
      "     VISIBLE:  'Volume 2 % slider', cursor=1",
-     "BRAILLE LINE:  '2 % $l'",
-     "     VISIBLE:  '2 % $l', cursor=0",
-     "BRAILLE LINE:  '2 % $l'",
-     "     VISIBLE:  '2 % $l', cursor=0",
      "SPEECH OUTPUT: '2 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -48,10 +40,6 @@ sequence.append(utils.AssertPresentationAction(
     "4. Volume Left Arrow",
     ["BRAILLE LINE:  'Volume 1 % slider'",
      "     VISIBLE:  'Volume 1 % slider', cursor=1",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
      "SPEECH OUTPUT: '1 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -60,10 +48,6 @@ sequence.append(utils.AssertPresentationAction(
     "5. Volume Left Arrow",
     ["BRAILLE LINE:  'Volume 0 % slider'",
      "     VISIBLE:  'Volume 0 % slider', cursor=1",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
      "SPEECH OUTPUT: '0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -72,10 +56,6 @@ sequence.append(utils.AssertPresentationAction(
     "6. Volume Up Arrow",
     ["BRAILLE LINE:  'Volume 1 % slider'",
      "     VISIBLE:  'Volume 1 % slider', cursor=1",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
      "SPEECH OUTPUT: '1 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -84,10 +64,6 @@ sequence.append(utils.AssertPresentationAction(
     "7. Volume Up Arrow",
     ["BRAILLE LINE:  'Volume 2 % slider'",
      "     VISIBLE:  'Volume 2 % slider', cursor=1",
-     "BRAILLE LINE:  '2 % $l'",
-     "     VISIBLE:  '2 % $l', cursor=0",
-     "BRAILLE LINE:  '2 % $l'",
-     "     VISIBLE:  '2 % $l', cursor=0",
      "SPEECH OUTPUT: '2 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -96,10 +72,6 @@ sequence.append(utils.AssertPresentationAction(
     "8. Volume Down Arrow",
     ["BRAILLE LINE:  'Volume 1 % slider'",
      "     VISIBLE:  'Volume 1 % slider', cursor=1",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
-     "BRAILLE LINE:  '1 % $l'",
-     "     VISIBLE:  '1 % $l', cursor=0",
      "SPEECH OUTPUT: '1 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -108,10 +80,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Volume Down Arrow",
     ["BRAILLE LINE:  'Volume 0 % slider'",
      "     VISIBLE:  'Volume 0 % slider', cursor=1",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
      "SPEECH OUTPUT: '0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -120,10 +88,6 @@ sequence.append(utils.AssertPresentationAction(
     "10. Volume Page Up",
     ["BRAILLE LINE:  'Volume 25 % slider'",
      "     VISIBLE:  'Volume 25 % slider', cursor=1",
-     "BRAILLE LINE:  '25 % $l'",
-     "     VISIBLE:  '25 % $l', cursor=0",
-     "BRAILLE LINE:  '25 % $l'",
-     "     VISIBLE:  '25 % $l', cursor=0",
      "SPEECH OUTPUT: '25 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -132,10 +96,6 @@ sequence.append(utils.AssertPresentationAction(
     "11. Volume Page Down",
     ["BRAILLE LINE:  'Volume 0 % slider'",
      "     VISIBLE:  'Volume 0 % slider', cursor=1",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
      "SPEECH OUTPUT: '0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -144,8 +104,6 @@ sequence.append(utils.AssertPresentationAction(
     "12. Volume End",
     ["BRAILLE LINE:  'Volume 100 % slider'",
      "     VISIBLE:  'Volume 100 % slider', cursor=1",
-     "BRAILLE LINE:  '100 % $l'",
-     "     VISIBLE:  '100 % $l', cursor=0",
      "SPEECH OUTPUT: '100 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -154,15 +112,13 @@ sequence.append(utils.AssertPresentationAction(
     "13. Volume Home",
     ["BRAILLE LINE:  'Volume 0 % slider'",
      "     VISIBLE:  'Volume 0 % slider', cursor=1",
-     "BRAILLE LINE:  '0 % $l'",
-     "     VISIBLE:  '0 % $l', cursor=0",
      "SPEECH OUTPUT: '0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "14. Tab to Food Quality Slider",
-    ["KNOWN ISSUE: We're double-speaking the slider name",
+    ["KNOWN ISSUE: The double-presentation is because of the authoring, putting the name and value into the 
description",
      "BRAILLE LINE:  'Food Quality terrible slider'",
      "     VISIBLE:  'Food Quality terrible slider', cursor=1",
      "SPEECH OUTPUT: 'Food Quality slider terrible Food Quality: terrible (1 of 5)'"]))
@@ -219,8 +175,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Page_Up"))
 sequence.append(utils.AssertPresentationAction(
     "21. Food Quality Page Up",
-    ["KNOWN ISSUE: We aren't presenting this",
-     "BRAILLE LINE:  'Food Quality bad slider'",
+    ["BRAILLE LINE:  'Food Quality bad slider'",
      "     VISIBLE:  'Food Quality bad slider', cursor=1",
      "SPEECH OUTPUT: 'bad'"]))
 
@@ -228,8 +183,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Page_Down"))
 sequence.append(utils.AssertPresentationAction(
     "22. Food Quality Page Down",
-    ["KNOWN ISSUE: We aren't presenting this",
-     "BRAILLE LINE:  'Food Quality terrible slider'",
+    ["BRAILLE LINE:  'Food Quality terrible slider'",
      "     VISIBLE:  'Food Quality terrible slider', cursor=1",
      "SPEECH OUTPUT: 'terrible'"]))
 
@@ -237,8 +191,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("End"))
 sequence.append(utils.AssertPresentationAction(
     "23. Food Quality End",
-    ["KNOWN ISSUE: We aren't presenting this",
-     "BRAILLE LINE:  'Food Quality excellent slider'",
+    ["BRAILLE LINE:  'Food Quality excellent slider'",
      "     VISIBLE:  'Food Quality excellent slider', cursor=1",
      "SPEECH OUTPUT: 'excellent'"]))
 
@@ -246,8 +199,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Home"))
 sequence.append(utils.AssertPresentationAction(
     "24. Food Quality Home",
-    ["KNOWN ISSUE: We aren't presenting this",
-     "BRAILLE LINE:  'Food Quality terrible slider'",
+    ["BRAILLE LINE:  'Food Quality terrible slider'",
      "     VISIBLE:  'Food Quality terrible slider', cursor=1",
      "SPEECH OUTPUT: 'terrible'"]))
 
diff --git a/test/keystrokes/firefox/aria_sliders.params b/test/keystrokes/firefox/aria_sliders.params
new file mode 100644
index 0000000..3205322
--- /dev/null
+++ b/test/keystrokes/firefox/aria_sliders.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-sliders.html
diff --git a/test/keystrokes/firefox/aria_slider_uiuc.py b/test/keystrokes/firefox/aria_sliders.py
similarity index 96%
rename from test/keystrokes/firefox/aria_slider_uiuc.py
rename to test/keystrokes/firefox/aria_sliders.py
index 75706b7..7c20f67 100644
--- a/test/keystrokes/firefox/aria_slider_uiuc.py
+++ b/test/keystrokes/firefox/aria_sliders.py
@@ -1,14 +1,13 @@
 #!/usr/bin/python
 
-"""Test of UIUC slider presentation."""
-
 from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
 
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
diff --git a/test/keystrokes/firefox/aria_tabpanel.py b/test/keystrokes/firefox/aria_tabpanel.py
index 27c1cc9..ade5319 100644
--- a/test/keystrokes/firefox/aria_tabpanel.py
+++ b/test/keystrokes/firefox/aria_tabpanel.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/aria_tabpanel2.params b/test/keystrokes/firefox/aria_tabpanel2.params
new file mode 100644
index 0000000..e6bfb89
--- /dev/null
+++ b/test/keystrokes/firefox/aria_tabpanel2.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-tabpanel2.html
diff --git a/test/keystrokes/firefox/aria_tabpanel_uiuc.py b/test/keystrokes/firefox/aria_tabpanel2.py
similarity index 93%
rename from test/keystrokes/firefox/aria_tabpanel_uiuc.py
rename to test/keystrokes/firefox/aria_tabpanel2.py
index 700d38b..5de724a 100644
--- a/test/keystrokes/firefox/aria_tabpanel_uiuc.py
+++ b/test/keystrokes/firefox/aria_tabpanel2.py
@@ -1,15 +1,13 @@
 #!/usr/bin/python
 
-"""Test of UIUC tab panel presentation."""
-
 from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
 
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
@@ -23,7 +21,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Page_Down"))
 sequence.append(utils.AssertPresentationAction(
     "2. Ctrl Page Down to second tab",
-    ["BRAILLE LINE:  'Crust page tab Veggies page tab Carnivore Delivery'",
+    ["BRAILLE LINE:  'Crust Veggies page tab Carnivore Delivery'",
      "     VISIBLE:  'Veggies page tab Carnivore Deliv', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
      "     VISIBLE:  'Focus mode', cursor=0",
diff --git a/test/keystrokes/firefox/aria_toolbar_dojo.py b/test/keystrokes/firefox/aria_toolbar_dojo.py
index c2a4fa1..b4a830a 100644
--- a/test/keystrokes/firefox/aria_toolbar_dojo.py
+++ b/test/keystrokes/firefox/aria_toolbar_dojo.py
@@ -37,7 +37,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "4. Down Arrow",
-    ["BRAILLE LINE:  'Buttons: Copy Toggles: Italic Dropdowns: TooltipDialog ColorPalette Combos: Menu save 
options push button Menu2 push button save options2 push button '",
+    ["BRAILLE LINE:  'Buttons: Copy Toggles: Italic Dropdowns: TooltipDialog ColorPalette  Combos: Menu save 
options push button Menu2 push button save options2 push button '",
      "     VISIBLE:  'Buttons: Copy Toggles: Italic Dr', cursor=1",
      "SPEECH OUTPUT: 'Buttons:'",
      "SPEECH OUTPUT: 'Copy'",
diff --git a/test/keystrokes/firefox/aria_tree.params b/test/keystrokes/firefox/aria_tree.params
new file mode 100644
index 0000000..2080a71
--- /dev/null
+++ b/test/keystrokes/firefox/aria_tree.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/aria-tree.html
diff --git a/test/keystrokes/firefox/aria_tree_uiuc.py b/test/keystrokes/firefox/aria_tree.py
similarity index 92%
rename from test/keystrokes/firefox/aria_tree_uiuc.py
rename to test/keystrokes/firefox/aria_tree.py
index 127ed63..357b14d 100644
--- a/test/keystrokes/firefox/aria_tree_uiuc.py
+++ b/test/keystrokes/firefox/aria_tree.py
@@ -1,15 +1,13 @@
 #!/usr/bin/python
 
-"""Test of UIUC tree presentation."""
-
 from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
 
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
-sequence.append(KeyComboAction("Tab"))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
@@ -66,8 +64,6 @@ sequence.append(utils.AssertPresentationAction(
     "6. Expand apples",
     ["BRAILLE LINE:  'Apples expanded list item'",
      "     VISIBLE:  'Apples expanded list item', cursor=1",
-     "BRAILLE LINE:  'Apples expanded list item'",
-     "     VISIBLE:  'Apples expanded list item', cursor=1",
      "SPEECH OUTPUT: 'expanded'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -94,8 +90,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Expand granny smith",
     ["BRAILLE LINE:  'Granny Smith expanded list item'",
      "     VISIBLE:  'Granny Smith expanded list item', cursor=1",
-     "BRAILLE LINE:  'Granny Smith expanded list item'",
-     "     VISIBLE:  'Granny Smith expanded list item', cursor=1",
      "SPEECH OUTPUT: 'expanded'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -172,8 +166,6 @@ sequence.append(utils.AssertPresentationAction(
     "17. Collapse vegetables",
     ["BRAILLE LINE:  'Vegetables collapsed list item'",
      "     VISIBLE:  'Vegetables collapsed list item', cursor=1",
-     "BRAILLE LINE:  'Vegetables collapsed list item'",
-     "     VISIBLE:  'Vegetables collapsed list item', cursor=1",
      "SPEECH OUTPUT: 'collapsed'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/aria_tree_dojo.py b/test/keystrokes/firefox/aria_tree_dojo.py
index ea98ea1..97be6b3 100644
--- a/test/keystrokes/firefox/aria_tree_dojo.py
+++ b/test/keystrokes/firefox/aria_tree_dojo.py
@@ -7,6 +7,7 @@ import utils
 
 sequence = MacroSequence()
 
+sequence.append(PauseAction(3000))
 sequence.append(KeyComboAction("Tab"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/aria_treegrid.py b/test/keystrokes/firefox/aria_treegrid.py
index 2558fa0..78d4741 100644
--- a/test/keystrokes/firefox/aria_treegrid.py
+++ b/test/keystrokes/firefox/aria_treegrid.py
@@ -15,8 +15,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '+A Question of Love', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
      "     VISIBLE:  'Focus mode', cursor=0",
-     "BRAILLE LINE:  '+A Question of Love table cell'",
-     "     VISIBLE:  '+A Question of Love table cell', cursor=1",
      "SPEECH OUTPUT: '+A Question of Love'",
      "SPEECH OUTPUT: 'Focus mode' voice=system"]))
 
@@ -24,8 +22,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "2. Down Arrow",
-    ["BRAILLE LINE:  '+ Piece of Peace table cell'",
-     "     VISIBLE:  '+ Piece of Peace table cell', cursor=1",
+    ["BRAILLE LINE:  '+A Question of Love'",
+     "     VISIBLE:  '+A Question of Love', cursor=1",
      "BRAILLE LINE:  '+ Piece of Peace table cell'",
      "     VISIBLE:  '+ Piece of Peace table cell', cursor=1",
      "SPEECH OUTPUT: '+ Piece of Peace'"]))
@@ -36,8 +34,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Down Arrow",
     ["BRAILLE LINE:  '+ International Law table cell'",
      "     VISIBLE:  '+ International Law table cell', cursor=1",
-     "BRAILLE LINE:  '+ International Law table cell'",
-     "     VISIBLE:  '+ International Law table cell', cursor=1",
      "SPEECH OUTPUT: '+ International Law'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -46,8 +42,6 @@ sequence.append(utils.AssertPresentationAction(
     "4. Up Arrow",
     ["BRAILLE LINE:  '+ Piece of Peace table cell'",
      "     VISIBLE:  '+ Piece of Peace table cell', cursor=1",
-     "BRAILLE LINE:  '+ Piece of Peace table cell'",
-     "     VISIBLE:  '+ Piece of Peace table cell', cursor=1",
      "SPEECH OUTPUT: '+ Piece of Peace'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -56,8 +50,6 @@ sequence.append(utils.AssertPresentationAction(
     "5. Up Arrow",
     ["BRAILLE LINE:  '+A Question of Love table cell'",
      "     VISIBLE:  '+A Question of Love table cell', cursor=1",
-     "BRAILLE LINE:  '+A Question of Love table cell'",
-     "     VISIBLE:  '+A Question of Love table cell', cursor=1",
      "SPEECH OUTPUT: '+A Question of Love'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -72,11 +64,11 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
 sequence.append(utils.AssertPresentationAction(
     "7. Space to expand the current item",
-    ["KNOWN ISSUE: Why aren't we also speaking this?",
+    ["BRAILLE LINE:  '-A Question of Love table row'",
+     "     VISIBLE:  '-A Question of Love table row', cursor=1",
      "BRAILLE LINE:  '-A Question of Love table cell'",
      "     VISIBLE:  '-A Question of Love table cell', cursor=1",
-     "BRAILLE LINE:  '-A Question of Love table cell'",
-     "     VISIBLE:  '-A Question of Love table cell', cursor=1"]))
+     "SPEECH OUTPUT: 'expanded'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
@@ -92,8 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Down Arrow into child",
     ["BRAILLE LINE:  '978-3-453-40540-0 table cell'",
      "     VISIBLE:  '978-3-453-40540-0 table cell', cursor=1",
-     "BRAILLE LINE:  '978-3-453-40540-0 table cell'",
-     "     VISIBLE:  '978-3-453-40540-0 table cell', cursor=1",
      "SPEECH OUTPUT: '978-3-453-40540-0'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -102,8 +92,6 @@ sequence.append(utils.AssertPresentationAction(
     "10. Right Arrow in child",
     ["BRAILLE LINE:  'Nora Roberts table cell'",
      "     VISIBLE:  'Nora Roberts table cell', cursor=1",
-     "BRAILLE LINE:  'Nora Roberts table cell'",
-     "     VISIBLE:  'Nora Roberts table cell', cursor=1",
      "SPEECH OUTPUT: 'Nora Roberts'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -112,8 +100,6 @@ sequence.append(utils.AssertPresentationAction(
     "11. Right Arrow in child",
     ["BRAILLE LINE:  '$ 9.99 table cell'",
      "     VISIBLE:  '$ 9.99 table cell', cursor=1",
-     "BRAILLE LINE:  '$ 9.99 table cell'",
-     "     VISIBLE:  '$ 9.99 table cell', cursor=1",
      "SPEECH OUTPUT: '$ 9.99'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -122,8 +108,6 @@ sequence.append(utils.AssertPresentationAction(
     "12. Left Arrow in child",
     ["BRAILLE LINE:  'Nora Roberts table cell'",
      "     VISIBLE:  'Nora Roberts table cell', cursor=1",
-     "BRAILLE LINE:  'Nora Roberts table cell'",
-     "     VISIBLE:  'Nora Roberts table cell', cursor=1",
      "SPEECH OUTPUT: 'Nora Roberts'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -132,8 +116,6 @@ sequence.append(utils.AssertPresentationAction(
     "13. Left Arrow in child",
     ["BRAILLE LINE:  '978-3-453-40540-0 table cell'",
      "     VISIBLE:  '978-3-453-40540-0 table cell', cursor=1",
-     "BRAILLE LINE:  '978-3-453-40540-0 table cell'",
-     "     VISIBLE:  '978-3-453-40540-0 table cell', cursor=1",
      "SPEECH OUTPUT: '978-3-453-40540-0'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -142,8 +124,6 @@ sequence.append(utils.AssertPresentationAction(
     "14. Up Arrow back to parent",
     ["BRAILLE LINE:  '-A Question of Love table cell'",
      "     VISIBLE:  '-A Question of Love table cell', cursor=1",
-     "BRAILLE LINE:  '-A Question of Love table cell'",
-     "     VISIBLE:  '-A Question of Love table cell', cursor=1",
      "SPEECH OUTPUT: '-A Question of Love'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/find_wiki.py b/test/keystrokes/firefox/find_wiki.py
index 1fc84e8..e2344c7 100644
--- a/test/keystrokes/firefox/find_wiki.py
+++ b/test/keystrokes/firefox/find_wiki.py
@@ -16,26 +16,16 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Return"))
 sequence.append(utils.AssertPresentationAction(
     "1. Return to next result",
-    ["KNOWN ISSUE: We're double-presenting this",
-     "BRAILLE LINE:  'Welcome to Orca! h1'",
+    ["BRAILLE LINE:  'Welcome to Orca! h1'",
      "     VISIBLE:  'Welcome to Orca! h1', cursor=12",
-     "BRAILLE LINE:  'Welcome to Orca! h1'",
-     "     VISIBLE:  'Welcome to Orca! h1', cursor=16",
-     "SPEECH OUTPUT: 'Welcome to Orca! heading level 1'",
      "SPEECH OUTPUT: 'Welcome to Orca! heading level 1'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Return"))
 sequence.append(utils.AssertPresentationAction(
     "2. Return to next result",
-    ["KNOWN ISSUE: We're double-presenting this",
-     "BRAILLE LINE:  'Welcome to Orca!'",
+    ["BRAILLE LINE:  'Welcome to Orca!'",
      "     VISIBLE:  'Welcome to Orca!', cursor=1",
-     "BRAILLE LINE:  'Welcome to Orca!'",
-     "     VISIBLE:  'Welcome to Orca!', cursor=1",
-     "SPEECH OUTPUT: '1.'",
-     "SPEECH OUTPUT: 'Welcome to Orca!'",
-     "SPEECH OUTPUT: 'link'",
      "SPEECH OUTPUT: '1.'",
      "SPEECH OUTPUT: 'Welcome to Orca!'",
      "SPEECH OUTPUT: 'link'"]))
@@ -44,24 +34,16 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Return"))
 sequence.append(utils.AssertPresentationAction(
     "3. Return to next result",
-    ["KNOWN ISSUE: We're double-presenting this",
-     "BRAILLE LINE:  'Orca is a free, open source, flexible, extensible, and  $l'",
+    ["BRAILLE LINE:  'Orca is a free, open source, flexible, extensible, and  $l'",
      "     VISIBLE:  'Orca is a free, open source, fle', cursor=1",
-     "BRAILLE LINE:  'Orca is a free, open source, flexible, extensible, and  $l'",
-     "     VISIBLE:  'Orca is a free, open source, fle', cursor=5",
-     "SPEECH OUTPUT: 'Orca is a free, open source, flexible, extensible, and'",
      "SPEECH OUTPUT: 'Orca is a free, open source, flexible, extensible, and'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Return"))
 sequence.append(utils.AssertPresentationAction(
     "4. Return to next result",
-    ["KNOWN ISSUE: We're double-presenting this",
-     "BRAILLE LINE:  'synthesis, braille, and magnification, Orca helps provide  $l'",
+    ["BRAILLE LINE:  'synthesis, braille, and magnification, Orca helps provide  $l'",
      "     VISIBLE:  's, braille, and magnification, O', cursor=32",
-     "BRAILLE LINE:  'synthesis, braille, and magnification, Orca helps provide  $l'",
-     "     VISIBLE:  'raille, and magnification, Orca ', cursor=32",
-     "SPEECH OUTPUT: 'synthesis, braille, and magnification, Orca helps provide'",
      "SPEECH OUTPUT: 'synthesis, braille, and magnification, Orca helps provide'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/flat_review_hidden_elements.py 
b/test/keystrokes/firefox/flat_review_hidden_elements.py
index 44bd651..b332f3b 100644
--- a/test/keystrokes/firefox/flat_review_hidden_elements.py
+++ b/test/keystrokes/firefox/flat_review_hidden_elements.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_8"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/flat_review_text_by_line.py 
b/test/keystrokes/firefox/flat_review_text_by_line.py
index c6db860..7ae38fb 100644
--- a/test/keystrokes/firefox/flat_review_text_by_line.py
+++ b/test/keystrokes/firefox/flat_review_text_by_line.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_8"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/flat_review_text_by_word_and_char.py 
b/test/keystrokes/firefox/flat_review_text_by_word_and_char.py
index 4cadb6d..aee7dae 100644
--- a/test/keystrokes/firefox/flat_review_text_by_word_and_char.py
+++ b/test/keystrokes/firefox/flat_review_text_by_word_and_char.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_5"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/focus_tracking_imagemap.py 
b/test/keystrokes/firefox/focus_tracking_imagemap.py
index 40f3517..d81f3ab 100644
--- a/test/keystrokes/firefox/focus_tracking_imagemap.py
+++ b/test/keystrokes/firefox/focus_tracking_imagemap.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
@@ -61,7 +65,7 @@ sequence.append(utils.AssertPresentationAction(
     "4. Tab",
     ["BRAILLE LINE:  'wk09_frozenmovie'",
      "     VISIBLE:  'wk09_frozenmovie', cursor=1",
-     "SPEECH OUTPUT: 'wk09_frozenmovie' voice=hyperlink",
+     "SPEECH OUTPUT: 'wk09_frozenmovie'",
      "SPEECH OUTPUT: 'link image'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/html_page_summary.py b/test/keystrokes/firefox/html_page_summary.py
index c4584e0..78063c5 100644
--- a/test/keystrokes/firefox/html_page_summary.py
+++ b/test/keystrokes/firefox/html_page_summary.py
@@ -26,7 +26,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'This is a Heading 6. h6'",
      "     VISIBLE:  'This is a Heading 6. h6', cursor=1",
      "SPEECH OUTPUT: 'heading level 6 This is a Heading 6.'",
-     "SPEECH OUTPUT: '14 headings 3 forms 47 tables'",
+     "SPEECH OUTPUT: '14 headings 3 forms 43 tables'",
      "SPEECH OUTPUT: '19 unvisited links'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/html_struct_nav_activate_link.py 
b/test/keystrokes/firefox/html_struct_nav_activate_link.py
index dd7748b..e6faab1 100644
--- a/test/keystrokes/firefox/html_struct_nav_activate_link.py
+++ b/test/keystrokes/firefox/html_struct_nav_activate_link.py
@@ -15,6 +15,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. Press 3 to move to the heading at level 3",
     ["BRAILLE LINE:  '1. Anchors2.html h3'",
      "     VISIBLE:  '1. Anchors2.html h3', cursor=4",
+     "BRAILLE LINE:  '1. Anchors2.html h3'",
+     "     VISIBLE:  '1. Anchors2.html h3', cursor=4",
      "SPEECH OUTPUT: 'Anchors2.html'",
      "SPEECH OUTPUT: 'link'",
      "SPEECH OUTPUT: 'heading level 3'"]))
diff --git a/test/keystrokes/firefox/html_struct_nav_bug_554616.py 
b/test/keystrokes/firefox/html_struct_nav_bug_554616.py
index 92b5765..d8f9257 100644
--- a/test/keystrokes/firefox/html_struct_nav_bug_554616.py
+++ b/test/keystrokes/firefox/html_struct_nav_bug_554616.py
@@ -18,8 +18,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Wrapping to top.', cursor=0",
      "BRAILLE LINE:  'table with 4 rows 3 columns'",
      "     VISIBLE:  'table with 4 rows 3 columns', cursor=0",
-     "BRAILLE LINE:  'Snapshot version'",
-     "     VISIBLE:  'Snapshot version', cursor=1",
+     "BRAILLE LINE:  'Snapshot version Date (UTC) Download'",
+     "     VISIBLE:  'Snapshot version Date (UTC) Down', cursor=1",
      "SPEECH OUTPUT: 'Wrapping to top.' voice=system",
      "SPEECH OUTPUT: 'table with 4 rows 3 columns' voice=system",
      "SPEECH OUTPUT: 'Snapshot version column header'"]))
@@ -57,7 +57,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Alt><Shift>Right"))
 sequence.append(utils.AssertPresentationAction(
     "4. Alt Shift Right",
-    ["BRAILLE LINE:  'r2477 Wed Nov 5 16:39:00 2008'",
+    ["KNOWN ISSUE: Excessive amount of updating here and in other assertions.",
+     "BRAILLE LINE:  'r2477 Wed Nov 5 16:39:00 2008'",
      "     VISIBLE:  'r2477 Wed Nov 5 16:39:00 2008', cursor=7",
      "BRAILLE LINE:  'installer (10190 KB)'",
      "     VISIBLE:  'installer (10190 KB)', cursor=1",
@@ -65,6 +66,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'installer (10190 KB)', cursor=1",
      "BRAILLE LINE:  'Row 2, column 3.'",
      "     VISIBLE:  'Row 2, column 3.', cursor=0",
+     "BRAILLE LINE:  'installer (10190 KB)'",
+     "     VISIBLE:  'installer (10190 KB)', cursor=1",
      "SPEECH OUTPUT: 'Download'",
      "SPEECH OUTPUT: 'installer'",
      "SPEECH OUTPUT: 'link'",
@@ -72,15 +75,14 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'portable archive'",
      "SPEECH OUTPUT: 'link'",
      "SPEECH OUTPUT: '(9154 KB)'",
-     "SPEECH OUTPUT: 'Row 2, column 3.' voice=system"]))
+     "SPEECH OUTPUT: 'Row 2, column 3.' voice=system",
+     "SPEECH OUTPUT: 'i'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Alt><Shift>Down"))
 sequence.append(utils.AssertPresentationAction(
     "5. Alt Shift Down",
-    ["BRAILLE LINE:  'installer (10190 KB)'",
-     "     VISIBLE:  'installer (10190 KB)', cursor=1",
-     "BRAILLE LINE:  'installer (10193 KB)'",
+    ["BRAILLE LINE:  'installer (10193 KB)'",
      "     VISIBLE:  'installer (10193 KB)', cursor=1",
      "BRAILLE LINE:  'installer (10193 KB)'",
      "     VISIBLE:  'installer (10193 KB)', cursor=1",
diff --git a/test/keystrokes/firefox/html_struct_nav_bug_567984.py 
b/test/keystrokes/firefox/html_struct_nav_bug_567984.py
index 8b9d647..0ecdd28 100644
--- a/test/keystrokes/firefox/html_struct_nav_bug_567984.py
+++ b/test/keystrokes/firefox/html_struct_nav_bug_567984.py
@@ -29,6 +29,8 @@ sequence.append(utils.AssertPresentationAction(
     "3. h",
     ["BRAILLE LINE:  'Izrael bejelentette az h3'",
      "     VISIBLE:  'Izrael bejelentette az h3', cursor=1",
+     "BRAILLE LINE:  'Izrael bejelentette az h3'",
+     "     VISIBLE:  'Izrael bejelentette az h3', cursor=1",
      "SPEECH OUTPUT: 'Izrael bejelentette az ",
      "egyoldalú tûzszünetet'",
      "SPEECH OUTPUT: 'link'",
diff --git a/test/keystrokes/firefox/html_struct_nav_descriptions.py 
b/test/keystrokes/firefox/html_struct_nav_descriptions.py
index 1c1c3f7..b284034 100644
--- a/test/keystrokes/firefox/html_struct_nav_descriptions.py
+++ b/test/keystrokes/firefox/html_struct_nav_descriptions.py
@@ -15,6 +15,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. k for next link",
     ["BRAILLE LINE:  'Foo, Bar, and Baz.'",
      "     VISIBLE:  'Foo, Bar, and Baz.', cursor=1",
+     "BRAILLE LINE:  'Foo, Bar, and Baz.'",
+     "     VISIBLE:  'Foo, Bar, and Baz.', cursor=1",
      "SPEECH OUTPUT: 'Foo'",
      "SPEECH OUTPUT: 'link Title of the Foo link.'"]))
 
diff --git a/test/keystrokes/firefox/html_struct_nav_heading_in_div_with_text.py 
b/test/keystrokes/firefox/html_struct_nav_heading_in_div_with_text.py
index b44889e..7f7d8f3 100644
--- a/test/keystrokes/firefox/html_struct_nav_heading_in_div_with_text.py
+++ b/test/keystrokes/firefox/html_struct_nav_heading_in_div_with_text.py
@@ -15,6 +15,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. 2 for first heading",
     ["BRAILLE LINE:  'First Heading h2'",
      "     VISIBLE:  'First Heading h2', cursor=1",
+     "BRAILLE LINE:  'First Heading h2'",
+     "     VISIBLE:  'First Heading h2', cursor=1",
      "SPEECH OUTPUT: 'First Heading'",
      "SPEECH OUTPUT: 'link'",
      "SPEECH OUTPUT: 'heading level 2'"]))
diff --git a/test/keystrokes/firefox/html_struct_nav_headings_buried_deep.py 
b/test/keystrokes/firefox/html_struct_nav_headings_buried_deep.py
index 22fbff3..ab5fd07 100644
--- a/test/keystrokes/firefox/html_struct_nav_headings_buried_deep.py
+++ b/test/keystrokes/firefox/html_struct_nav_headings_buried_deep.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/html_struct_nav_links.py 
b/test/keystrokes/firefox/html_struct_nav_links.py
index 845e485..962c6d2 100644
--- a/test/keystrokes/firefox/html_struct_nav_links.py
+++ b/test/keystrokes/firefox/html_struct_nav_links.py
@@ -15,6 +15,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. u to anchors.html link",
     ["BRAILLE LINE:  '• anchors.html'",
      "     VISIBLE:  '• anchors.html', cursor=3",
+     "BRAILLE LINE:  '• anchors.html'",
+     "     VISIBLE:  '• anchors.html', cursor=3",
      "SPEECH OUTPUT: 'anchors.html'",
      "SPEECH OUTPUT: 'link'"]))
 
diff --git a/test/keystrokes/firefox/label_inference_bug_546815.py 
b/test/keystrokes/firefox/label_inference_bug_546815.py
index 0b34f71..72e7032 100644
--- a/test/keystrokes/firefox/label_inference_bug_546815.py
+++ b/test/keystrokes/firefox/label_inference_bug_546815.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(PauseAction(3000))
 
@@ -36,7 +40,7 @@ sequence.append(KeyComboAction("Tab"))
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "3. Next form field",
-    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using'",
+    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using value'",
      "     VISIBLE:  ' $l 3. Enter your State:  $l 4. ', cursor=1",
      "SPEECH OUTPUT: '2. Enter your City: entry'"]))
 
@@ -46,7 +50,7 @@ sequence.append(KeyComboAction("Tab"))
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "4. Next form field",
-    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using'",
+    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using value'",
      "     VISIBLE:  ' $l 4. Enter your Country: US $l', cursor=1",
      "SPEECH OUTPUT: '3. Enter your State: entry'"]))
 
@@ -56,8 +60,8 @@ sequence.append(KeyComboAction("Tab"))
 sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "5. Next form field",
-    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using'",
-     "     VISIBLE:  'US $l image text field using', cursor=1",
+    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using value'",
+     "     VISIBLE:  'US $l image text field using val', cursor=1",
      "SPEECH OUTPUT: '4. Enter your Country: entry'",
      "SPEECH OUTPUT: 'US'"]))
 
diff --git a/test/keystrokes/firefox/label_inference_bugzilla_search.py 
b/test/keystrokes/firefox/label_inference_bugzilla_search.py
index f231442..9a72d4c 100644
--- a/test/keystrokes/firefox/label_inference_bugzilla_search.py
+++ b/test/keystrokes/firefox/label_inference_bugzilla_search.py
@@ -46,6 +46,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Admin', cursor=1",
      "BRAILLE LINE:  'Focus mode'",
      "     VISIBLE:  'Focus mode', cursor=0",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Classification: multi-select List with 8 items'",
      "SPEECH OUTPUT: 'Admin '",
      "SPEECH OUTPUT: 'Focus mode' voice=system"]))
@@ -58,6 +59,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Admin', cursor=1",
      "BRAILLE LINE:  'accerciser'",
      "     VISIBLE:  'accerciser', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Product: multi-select List with 379 items'",
      "SPEECH OUTPUT: 'accerciser'"]))
 
@@ -94,6 +96,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'abiscan', cursor=1",
      "BRAILLE LINE:  '0.0.1'",
      "     VISIBLE:  '0.0.1', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Version: multi-select List with 857 items'",
      "SPEECH OUTPUT: '0.0.1'"]))
 
@@ -103,6 +106,7 @@ sequence.append(utils.AssertPresentationAction(
     "9. Tab",
     ["BRAILLE LINE:  '---'",
      "     VISIBLE:  '---', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Target Milestone: multi-select List with 555 items'",
      "SPEECH OUTPUT: '---'"]))
 
@@ -178,6 +182,7 @@ sequence.append(utils.AssertPresentationAction(
     "17. Tab",
     ["BRAILLE LINE:  'UNCONFIRMED'",
      "     VISIBLE:  'UNCONFIRMED', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Status: multi-select List with 8 items'",
      "SPEECH OUTPUT: 'UNCONFIRMED'"]))
 
@@ -187,6 +192,7 @@ sequence.append(utils.AssertPresentationAction(
     "18. Tab",
     ["BRAILLE LINE:  'FIXED'",
      "     VISIBLE:  'FIXED', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Resolution: multi-select List with 12 items'",
      "SPEECH OUTPUT: 'FIXED'"]))
 
@@ -196,6 +202,7 @@ sequence.append(utils.AssertPresentationAction(
     "19. Tab",
     ["BRAILLE LINE:  'blocker'",
      "     VISIBLE:  'blocker', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Severity: multi-select List with 7 items'",
      "SPEECH OUTPUT: 'blocker'"]))
 
@@ -205,6 +212,7 @@ sequence.append(utils.AssertPresentationAction(
     "20. Tab",
     ["BRAILLE LINE:  'Immediate'",
      "     VISIBLE:  'Immediate', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'Priority: multi-select List with 5 items'",
      "SPEECH OUTPUT: 'Immediate'"]))
 
@@ -214,6 +222,7 @@ sequence.append(utils.AssertPresentationAction(
     "21. Tab",
     ["BRAILLE LINE:  'All'",
      "     VISIBLE:  'All', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'OS: multi-select List with 21 items'",
      "SPEECH OUTPUT: 'All'"]))
 
@@ -410,6 +419,7 @@ sequence.append(utils.AssertPresentationAction(
     "42. Tab",
     ["BRAILLE LINE:  'Unspecified'",
      "     VISIBLE:  'Unspecified', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'GNOME version: multi-select List with 14 items'",
      "SPEECH OUTPUT: 'Unspecified'"]))
 
@@ -419,6 +429,7 @@ sequence.append(utils.AssertPresentationAction(
     "43. Tab",
     ["BRAILLE LINE:  'Unspecified'",
      "     VISIBLE:  'Unspecified', cursor=1",
+     "SPEECH OUTPUT: 'table with 2 rows 1 column'",
      "SPEECH OUTPUT: 'GNOME target: multi-select List with 12 items'",
      "SPEECH OUTPUT: 'Unspecified'"]))
 
diff --git a/test/keystrokes/firefox/label_inference_entries.py 
b/test/keystrokes/firefox/label_inference_entries.py
index 2a85d36..daa84a4 100644
--- a/test/keystrokes/firefox/label_inference_entries.py
+++ b/test/keystrokes/firefox/label_inference_entries.py
@@ -8,6 +8,7 @@ sequence = MacroSequence()
 sequence.append(PauseAction(3000))
 sequence.append(KeyComboAction("Tab"))
 sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(PauseAction(3000))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
@@ -59,7 +60,7 @@ sequence.append(utils.AssertPresentationAction(
     "5. Next form field",
     ["BRAILLE LINE:  ' $l Am I a label as well?'",
      "     VISIBLE:  ' $l Am I a label as well?', cursor=1",
-     "SPEECH OUTPUT: 'Am I a label as well? entry'"]))
+     "SPEECH OUTPUT: 'entry'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
diff --git a/test/keystrokes/firefox/line_nav_bug_546815.py b/test/keystrokes/firefox/line_nav_bug_546815.py
index 93aca24..5fb302c 100644
--- a/test/keystrokes/firefox/line_nav_bug_546815.py
+++ b/test/keystrokes/firefox/line_nav_bug_546815.py
@@ -7,6 +7,9 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 sequence.append(PauseAction(3000))
 
 sequence.append(utils.StartRecordingAction())
@@ -63,27 +66,19 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "7. Line Down",
-    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using'",
+    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using value'",
      "     VISIBLE:  '2. Enter your City:  $l 3. Enter', cursor=1",
      "SPEECH OUTPUT: '2. Enter your City: entry'",
      "SPEECH OUTPUT: '3. Enter your State: entry'",
      "SPEECH OUTPUT: '4. Enter your Country: entry'",
      "SPEECH OUTPUT: 'US'",
      "SPEECH OUTPUT: 'image'",
-     "SPEECH OUTPUT: 'text field using'"]))
+     "SPEECH OUTPUT: 'text field using value'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "8. Line Down",
-    ["BRAILLE LINE:  'value'",
-     "     VISIBLE:  'value', cursor=1",
-     "SPEECH OUTPUT: 'value'"]))
-
-sequence.append(utils.StartRecordingAction())
-sequence.append(KeyComboAction("Down"))
-sequence.append(utils.AssertPresentationAction(
-    "9. Line Down",
     ["BRAILLE LINE:  '5. Enter your Zip:  $l'",
      "     VISIBLE:  '5. Enter your Zip:  $l', cursor=1",
      "SPEECH OUTPUT: '5. Enter your Zip: entry'"]))
@@ -91,7 +86,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "10. Line Down",
+    "9. Line Down",
     ["BRAILLE LINE:  '6. What happens when a fixed-width font(the default) is used for a one-byte text input 
area, let's try it.. Enter one'",
      "     VISIBLE:  '6. What happens when a fixed-wid', cursor=1",
      "SPEECH OUTPUT: '6. What happens when a fixed-width font(the default) is used for a one-byte text input 
area, let's try it.. Enter one'"]))
@@ -99,7 +94,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "11. Line Down",
+    "10. Line Down",
     ["BRAILLE LINE:  'character:  $l'",
      "     VISIBLE:  'character:  $l', cursor=1",
      "SPEECH OUTPUT: 'character: entry'"]))
@@ -107,7 +102,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "12. Line Down",
+    "11. Line Down",
     ["BRAILLE LINE:  'separator'",
      "     VISIBLE:  'separator', cursor=1",
      "SPEECH OUTPUT: 'separator'"]))
@@ -115,7 +110,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "13. Line Down",
+    "12. Line Down",
     ["BRAILLE LINE:  ' CheckBox:'",
      "     VISIBLE:  ' CheckBox:', cursor=1",
      "SPEECH OUTPUT: 'CheckBox:'"]))
@@ -123,7 +118,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "14. Line Down",
+    "13. Line Down",
     ["BRAILLE LINE:  'What are your favorite pets? h2'",
      "     VISIBLE:  'What are your favorite pets? h2', cursor=1",
      "SPEECH OUTPUT: 'What are your favorite pets? heading level 2'"]))
@@ -131,7 +126,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "15. Line Down",
+    "14. Line Down",
     ["BRAILLE LINE:  '< > check box bird'",
      "     VISIBLE:  '< > check box bird', cursor=1",
      "SPEECH OUTPUT: 'bird check box not checked'"]))
@@ -139,7 +134,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "16. Line Down",
+    "15. Line Down",
     ["BRAILLE LINE:  '< > check box fish'",
      "     VISIBLE:  '< > check box fish', cursor=1",
      "SPEECH OUTPUT: 'fish check box not checked'"]))
@@ -147,7 +142,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "17. Line Down",
+    "16. Line Down",
     ["BRAILLE LINE:  '< > check box wild animal'",
      "     VISIBLE:  '< > check box wild animal', cursor=1",
      "SPEECH OUTPUT: 'wild animal check box not checked'"]))
@@ -155,7 +150,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "18. Line Down",
+    "17. Line Down",
     ["BRAILLE LINE:  'separator'",
      "     VISIBLE:  'separator', cursor=1",
      "SPEECH OUTPUT: 'separator'"]))
@@ -163,7 +158,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "19. Line Down",
+    "18. Line Down",
     ["BRAILLE LINE:  'Radio Buttons:'",
      "     VISIBLE:  'Radio Buttons:', cursor=1",
      "SPEECH OUTPUT: 'Radio Buttons:'"]))
@@ -171,7 +166,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "20. Line Down",
+    "19. Line Down",
     ["BRAILLE LINE:  'Would type of wine do you like? h2'",
      "     VISIBLE:  'Would type of wine do you like? ', cursor=1",
      "SPEECH OUTPUT: 'Would type of wine do you like? heading level 2'"]))
@@ -179,7 +174,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "21. Line Down",
+    "20. Line Down",
     ["BRAILLE LINE:  '&=y radio button cabernet sauvignon'",
      "     VISIBLE:  '&=y radio button cabernet sauvig', cursor=1",
      "SPEECH OUTPUT: 'cabernet sauvignon selected radio button'"]))
@@ -187,7 +182,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "22. Line Down",
+    "21. Line Down",
     ["BRAILLE LINE:  '& y radio button merlot'",
      "     VISIBLE:  '& y radio button merlot', cursor=1",
      "SPEECH OUTPUT: 'merlot not selected radio button'"]))
@@ -195,7 +190,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "23. Line Down",
+    "22. Line Down",
     ["BRAILLE LINE:  '& y radio button nebbiolo'",
      "     VISIBLE:  '& y radio button nebbiolo', cursor=1",
      "SPEECH OUTPUT: 'nebbiolo not selected radio button'"]))
@@ -203,7 +198,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "24. Line Down",
+    "23. Line Down",
     ["BRAILLE LINE:  '& y radio button pinot noir'",
      "     VISIBLE:  '& y radio button pinot noir', cursor=1",
      "SPEECH OUTPUT: 'pinot noir not selected radio button'"]))
@@ -211,7 +206,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "25. Line Down",
+    "24. Line Down",
     ["BRAILLE LINE:  '& y radio button don't drink wine'",
      "     VISIBLE:  '& y radio button don't drink win', cursor=1",
      "SPEECH OUTPUT: 'don't drink wine not selected radio button'"]))
@@ -219,7 +214,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "26. Line Up",
+    "25. Line Up",
     ["BRAILLE LINE:  '& y radio button pinot noir'",
      "     VISIBLE:  '& y radio button pinot noir', cursor=1",
      "SPEECH OUTPUT: 'pinot noir not selected radio button'"]))
@@ -227,7 +222,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "27. Line Up",
+    "26. Line Up",
     ["BRAILLE LINE:  '& y radio button nebbiolo'",
      "     VISIBLE:  '& y radio button nebbiolo', cursor=1",
      "SPEECH OUTPUT: 'nebbiolo not selected radio button'"]))
@@ -235,7 +230,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "28. Line Up",
+    "27. Line Up",
     ["BRAILLE LINE:  '& y radio button merlot'",
      "     VISIBLE:  '& y radio button merlot', cursor=1",
      "SPEECH OUTPUT: 'merlot not selected radio button'"]))
@@ -243,7 +238,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "29. Line Up",
+    "28. Line Up",
     ["BRAILLE LINE:  '&=y radio button cabernet sauvignon'",
      "     VISIBLE:  '&=y radio button cabernet sauvig', cursor=1",
      "SPEECH OUTPUT: 'cabernet sauvignon selected radio button'"]))
@@ -251,7 +246,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "30. Line Up",
+    "29. Line Up",
     ["BRAILLE LINE:  'Would type of wine do you like? h2'",
      "     VISIBLE:  'Would type of wine do you like? ', cursor=1",
      "SPEECH OUTPUT: 'Would type of wine do you like? heading level 2'"]))
@@ -259,7 +254,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "31. Line Up",
+    "30. Line Up",
     ["BRAILLE LINE:  'Radio Buttons:'",
      "     VISIBLE:  'Radio Buttons:', cursor=1",
      "SPEECH OUTPUT: 'Radio Buttons:'"]))
@@ -267,7 +262,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "32. Line Up",
+    "31. Line Up",
     ["BRAILLE LINE:  'separator'",
      "     VISIBLE:  'separator', cursor=1",
      "SPEECH OUTPUT: 'separator'"]))
@@ -275,7 +270,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "33. Line Up",
+    "32. Line Up",
     ["BRAILLE LINE:  '< > check box wild animal'",
      "     VISIBLE:  '< > check box wild animal', cursor=1",
      "SPEECH OUTPUT: 'wild animal check box not checked'"]))
@@ -283,7 +278,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "34. Line Up",
+    "33. Line Up",
     ["BRAILLE LINE:  '< > check box fish'",
      "     VISIBLE:  '< > check box fish', cursor=1",
      "SPEECH OUTPUT: 'fish check box not checked'"]))
@@ -291,7 +286,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "35. Line Up",
+    "34. Line Up",
     ["BRAILLE LINE:  '< > check box bird'",
      "     VISIBLE:  '< > check box bird', cursor=1",
      "SPEECH OUTPUT: 'bird check box not checked'"]))
@@ -299,7 +294,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "36. Line Up",
+    "35. Line Up",
     ["BRAILLE LINE:  'What are your favorite pets? h2'",
      "     VISIBLE:  'What are your favorite pets? h2', cursor=1",
      "SPEECH OUTPUT: 'What are your favorite pets? heading level 2'"]))
@@ -307,7 +302,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "37. Line Up",
+    "36. Line Up",
     ["BRAILLE LINE:  ' CheckBox:'",
      "     VISIBLE:  ' CheckBox:', cursor=1",
      "SPEECH OUTPUT: 'CheckBox:'"]))
@@ -315,7 +310,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "38. Line Up",
+    "37. Line Up",
     ["BRAILLE LINE:  'separator'",
      "     VISIBLE:  'separator', cursor=1",
      "SPEECH OUTPUT: 'separator'"]))
@@ -323,7 +318,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "39. Line Up",
+    "38. Line Up",
     ["BRAILLE LINE:  'character:  $l'",
      "     VISIBLE:  'character:  $l', cursor=1",
      "SPEECH OUTPUT: 'character: entry'"]))
@@ -331,7 +326,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "40. Line Up",
+    "39. Line Up",
     ["BRAILLE LINE:  '6. What happens when a fixed-width font(the default) is used for a one-byte text input 
area, let's try it.. Enter one'",
      "     VISIBLE:  '6. What happens when a fixed-wid', cursor=1",
      "SPEECH OUTPUT: '6. What happens when a fixed-width font(the default) is used for a one-byte text input 
area, let's try it.. Enter one'"]))
@@ -339,7 +334,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "41. Line Up",
+    "40. Line Up",
     ["BRAILLE LINE:  '5. Enter your Zip:  $l'",
      "     VISIBLE:  '5. Enter your Zip:  $l', cursor=1",
      "SPEECH OUTPUT: '5. Enter your Zip: entry'"]))
@@ -347,28 +342,20 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "42. Line Up",
-    ["BRAILLE LINE:  'value'",
-     "     VISIBLE:  'value', cursor=1",
-     "SPEECH OUTPUT: 'value'"]))
-
-sequence.append(utils.StartRecordingAction())
-sequence.append(KeyComboAction("Up"))
-sequence.append(utils.AssertPresentationAction(
-    "43. Line Up",
-    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using'",
+    "41. Line Up",
+    ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l image 
text field using value'",
      "     VISIBLE:  '2. Enter your City:  $l 3. Enter', cursor=1",
      "SPEECH OUTPUT: '2. Enter your City: entry'",
      "SPEECH OUTPUT: '3. Enter your State: entry'",
      "SPEECH OUTPUT: '4. Enter your Country: entry'",
      "SPEECH OUTPUT: 'US'",
      "SPEECH OUTPUT: 'image'",
-     "SPEECH OUTPUT: 'text field using'"]))
+     "SPEECH OUTPUT: 'text field using value'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "44. Line Up",
+    "42. Line Up",
     ["BRAILLE LINE:  'MAXLENGTH'",
      "     VISIBLE:  'MAXLENGTH', cursor=1",
      "SPEECH OUTPUT: 'MAXLENGTH'"]))
@@ -376,7 +363,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "45. Line Up",
+    "43. Line Up",
     ["BRAILLE LINE:  '1. Enter your Address:  $l text field using SIZE and'",
      "     VISIBLE:  '1. Enter your Address:  $l text ', cursor=1",
      "SPEECH OUTPUT: '1. Enter your Address: entry'",
@@ -385,7 +372,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "46. Line Up",
+    "44. Line Up",
     ["BRAILLE LINE:  'Enter your Name:  $l text field using default type=text'",
      "     VISIBLE:  'Enter your Name:  $l text field ', cursor=1",
      "SPEECH OUTPUT: 'Enter your Name: entry'",
@@ -394,7 +381,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "47. Line Up",
+    "45. Line Up",
     ["BRAILLE LINE:  'Textfield :'",
      "     VISIBLE:  'Textfield :', cursor=1",
      "SPEECH OUTPUT: 'Textfield :'"]))
@@ -402,7 +389,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "48. Line Up",
+    "46. Line Up",
     ["BRAILLE LINE:  'HTML Form and Widgets'",
      "     VISIBLE:  'HTML Form and Widgets', cursor=1",
      "SPEECH OUTPUT: 'HTML Form and Widgets'"]))
@@ -410,7 +397,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "49. Line Up",
+    "47. Line Up",
     ["BRAILLE LINE:  'separator'",
      "     VISIBLE:  'separator', cursor=1",
      "SPEECH OUTPUT: 'separator'"]))
diff --git a/test/keystrokes/firefox/line_nav_bug_549128.py b/test/keystrokes/firefox/line_nav_bug_549128.py
index 97d4f54..a9ca72f 100644
--- a/test/keystrokes/firefox/line_nav_bug_549128.py
+++ b/test/keystrokes/firefox/line_nav_bug_549128.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_bug_552887a.py b/test/keystrokes/firefox/line_nav_bug_552887a.py
index 58391aa..ca1f871 100644
--- a/test/keystrokes/firefox/line_nav_bug_552887a.py
+++ b/test/keystrokes/firefox/line_nav_bug_552887a.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_bugzilla_search_down.py 
b/test/keystrokes/firefox/line_nav_bugzilla_search_down.py
index 06ef2ab..caaa1db 100644
--- a/test/keystrokes/firefox/line_nav_bugzilla_search_down.py
+++ b/test/keystrokes/firefox/line_nav_bugzilla_search_down.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(PauseAction(3000))
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
 sequence.append(KeyComboAction("a"))
diff --git a/test/keystrokes/firefox/line_nav_bugzilla_search_up.py 
b/test/keystrokes/firefox/line_nav_bugzilla_search_up.py
index 7ee2735..c43731f 100644
--- a/test/keystrokes/firefox/line_nav_bugzilla_search_up.py
+++ b/test/keystrokes/firefox/line_nav_bugzilla_search_up.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(PauseAction(3000))
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
 sequence.append(KeyComboAction("a"))
diff --git a/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py 
b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py
index d735dc0..afbc663 100644
--- a/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py
+++ b/test/keystrokes/firefox/line_nav_button_in_link_position_relative_on_focus.py
@@ -5,6 +5,9 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/line_nav_clickables.py b/test/keystrokes/firefox/line_nav_clickables.py
index 3fd2c5f..2ff5e04 100644
--- a/test/keystrokes/firefox/line_nav_clickables.py
+++ b/test/keystrokes/firefox/line_nav_clickables.py
@@ -7,7 +7,9 @@ import utils
 
 sequence = MacroSequence()
 
-sequence.append(PauseAction(3000))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(KeyComboAction("Down"))
 
diff --git a/test/keystrokes/firefox/line_nav_descriptions.py 
b/test/keystrokes/firefox/line_nav_descriptions.py
index 08c8125..fee615f 100644
--- a/test/keystrokes/firefox/line_nav_descriptions.py
+++ b/test/keystrokes/firefox/line_nav_descriptions.py
@@ -7,6 +7,9 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/line_nav_empty_anchor.py 
b/test/keystrokes/firefox/line_nav_empty_anchor.py
index 0fe30cc..93035e3 100644
--- a/test/keystrokes/firefox/line_nav_empty_anchor.py
+++ b/test/keystrokes/firefox/line_nav_empty_anchor.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_empty_textarea.py 
b/test/keystrokes/firefox/line_nav_empty_textarea.py
index a20cc08..42dc261 100644
--- a/test/keystrokes/firefox/line_nav_empty_textarea.py
+++ b/test/keystrokes/firefox/line_nav_empty_textarea.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_enter_bug.py b/test/keystrokes/firefox/line_nav_enter_bug.py
index 7e1f55d..b012ad1 100644
--- a/test/keystrokes/firefox/line_nav_enter_bug.py
+++ b/test/keystrokes/firefox/line_nav_enter_bug.py
@@ -285,29 +285,31 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "29. Line Down",
-    ["BRAILLE LINE:  'Keywords:'",
-     "     VISIBLE:  'Keywords:', cursor=1",
+    ["BRAILLE LINE:  'Keywords:  $l'",
+     "     VISIBLE:  'Keywords:  $l', cursor=1",
      "SPEECH OUTPUT: 'Keywords'",
      "SPEECH OUTPUT: 'link'",
-     "SPEECH OUTPUT: ':'"]))
+     "SPEECH OUTPUT: ':'",
+     "SPEECH OUTPUT: 'Keywords: entry'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "30. Line Down",
-    ["BRAILLE LINE:  ' $l'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: 'Keywords: entry'"]))
+    ["BRAILLE LINE:  'Depends'",
+     "     VISIBLE:  'Depends', cursor=1",
+     "SPEECH OUTPUT: 'Depends'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "31. Line Up",
-    ["BRAILLE LINE:  'Keywords:'",
-     "     VISIBLE:  'Keywords:', cursor=1",
+    ["BRAILLE LINE:  'Keywords:  $l'",
+     "     VISIBLE:  'Keywords:  $l', cursor=1",
      "SPEECH OUTPUT: 'Keywords'",
      "SPEECH OUTPUT: 'link'",
-     "SPEECH OUTPUT: ':'"]))
+     "SPEECH OUTPUT: ':'",
+     "SPEECH OUTPUT: 'Keywords: entry'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/line_nav_entries.py b/test/keystrokes/firefox/line_nav_entries.py
index 037c508..f70bc19 100644
--- a/test/keystrokes/firefox/line_nav_entries.py
+++ b/test/keystrokes/firefox/line_nav_entries.py
@@ -7,7 +7,9 @@ import utils
 
 sequence = MacroSequence()
 
-sequence.append(PauseAction(3000))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
@@ -57,7 +59,8 @@ sequence.append(utils.AssertPresentationAction(
     "5. Line Down",
     ["BRAILLE LINE:  ' $l Am I a label as well?'",
      "     VISIBLE:  ' $l Am I a label as well?', cursor=1",
-     "SPEECH OUTPUT: 'Am I a label as well? entry'"]))
+     "SPEECH OUTPUT: 'entry'",
+     "SPEECH OUTPUT: 'Am I a label as well?'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -476,7 +479,8 @@ sequence.append(utils.AssertPresentationAction(
     "55. Line Up",
     ["BRAILLE LINE:  ' $l Am I a label as well?'",
      "     VISIBLE:  ' $l Am I a label as well?', cursor=1",
-     "SPEECH OUTPUT: 'Am I a label as well? entry'"]))
+     "SPEECH OUTPUT: 'entry'",
+     "SPEECH OUTPUT: 'Am I a label as well?'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/line_nav_follow_same_page_link_2.py 
b/test/keystrokes/firefox/line_nav_follow_same_page_link_2.py
index 2ff0302..5a73f35 100644
--- a/test/keystrokes/firefox/line_nav_follow_same_page_link_2.py
+++ b/test/keystrokes/firefox/line_nav_follow_same_page_link_2.py
@@ -7,6 +7,9 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
 sequence.append(PauseAction(3000))
 sequence.append(KeyComboAction("<Control>Home"))
 for i in range(25):
@@ -16,9 +19,11 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Return"))
 sequence.append(utils.AssertPresentationAction(
     "Return to activate the same-page link for the About heading",
-    ["KNOWN ISSUE: We are not speaking this.",
-     "BRAILLE LINE:  '2. About'",
-     "     VISIBLE:  '2. About', cursor=4"]))
+    ["BRAILLE LINE:  '2. About'",
+     "     VISIBLE:  '2. About', cursor=4",
+     "BRAILLE LINE:  'About h1'",
+     "     VISIBLE:  'About h1', cursor=1",
+     "SPEECH OUTPUT: 'About heading level 1'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
diff --git a/test/keystrokes/firefox/line_nav_hidden_label.py 
b/test/keystrokes/firefox/line_nav_hidden_label.py
index b273aa2..ba299b3 100644
--- a/test/keystrokes/firefox/line_nav_hidden_label.py
+++ b/test/keystrokes/firefox/line_nav_hidden_label.py
@@ -29,6 +29,16 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "3. Line Down",
+    ["KNOWN ISSUE: We're double-presenting this. Might be due to a zombie.",
+     "BRAILLE LINE:  '< > I am a hidden label!   Check me! check box image'",
+     "     VISIBLE:  '< > I am a hidden label!   Check', cursor=1",
+     "SPEECH OUTPUT: 'I am a hidden label!   Check me! check box not checked'",
+     "SPEECH OUTPUT: 'image'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
     ["KNOWN ISSUE: We're displaying part of the hidden label",
      "BRAILLE LINE:  'I '",
      "     VISIBLE:  'I ', cursor=1",
@@ -37,7 +47,7 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
-    "4. Line Down",
+    "5. Line Down",
     ["BRAILLE LINE:  'End'",
      "     VISIBLE:  'End', cursor=1",
      "SPEECH OUTPUT: 'End'"]))
@@ -45,15 +55,25 @@ sequence.append(utils.AssertPresentationAction(
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "5. Line Up",
-    ["BRAILLE LINE:  '< > I am a hidden label!   Check me! check box'",
+    "6. Line Up",
+    ["KNOWN ISSUE: We're displaying the hidden label",
+     "BRAILLE LINE:  'I am a hidden label!   Check me!'",
+     "     VISIBLE:  'I am a hidden label!   Check me!', cursor=1",
+     "SPEECH OUTPUT: 'blank'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Up",
+    ["BRAILLE LINE:  '< > I am a hidden label!   Check me! check box image'",
      "     VISIBLE:  '< > I am a hidden label!   Check', cursor=1",
-     "SPEECH OUTPUT: 'I am a hidden label!   Check me! check box not checked'"]))
+     "SPEECH OUTPUT: 'I am a hidden label!   Check me! check box not checked'",
+     "SPEECH OUTPUT: 'image'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
-    "6. Line Up",
+    "8. Line Up",
     ["BRAILLE LINE:  'Start'",
      "     VISIBLE:  'Start', cursor=1",
      "SPEECH OUTPUT: 'Start'"]))
diff --git a/test/keystrokes/firefox/line_nav_home_end_on_blank_line.py 
b/test/keystrokes/firefox/line_nav_home_end_on_blank_line.py
index 0eb1f37..897a2cf 100644
--- a/test/keystrokes/firefox/line_nav_home_end_on_blank_line.py
+++ b/test/keystrokes/firefox/line_nav_home_end_on_blank_line.py
@@ -6,6 +6,11 @@ from macaroon.playback import *
 import utils
 
 sequence = MacroSequence()
+
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(KeyComboAction("End"))
 sequence.append(KeyComboAction("Right"))
diff --git a/test/keystrokes/firefox/line_nav_iframes_in_inline_block.py 
b/test/keystrokes/firefox/line_nav_iframes_in_inline_block.py
index 0747a4b..1a3f4c6 100644
--- a/test/keystrokes/firefox/line_nav_iframes_in_inline_block.py
+++ b/test/keystrokes/firefox/line_nav_iframes_in_inline_block.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.params 
b/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.params
new file mode 100644
index 0000000..a661ab5
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/iframes-inside-inline-block2.html
diff --git a/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.py 
b/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.py
new file mode 100644
index 0000000..6e3c4ee
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_iframes_in_inline_block2.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+"""Test of line navigation output of Firefox."""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Top of file",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  'No abbreviation here.'",
+     "     VISIBLE:  'No abbreviation here.', cursor=1",
+     "SPEECH OUTPUT: 'No abbreviation here.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'WHATWG started working on'",
+     "     VISIBLE:  'WHATWG started working on', cursor=1",
+     "SPEECH OUTPUT: 'WHATWG'",
+     "SPEECH OUTPUT: 'started working on'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
+    ["BRAILLE LINE:  'HTML5 in 2004.'",
+     "     VISIBLE:  'HTML5 in 2004.', cursor=1",
+     "SPEECH OUTPUT: 'HTML5 in 2004.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Down",
+    ["BRAILLE LINE:  'No abbreviation here either.'",
+     "     VISIBLE:  'No abbreviation here either.', cursor=1",
+     "SPEECH OUTPUT: 'No abbreviation here either.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "6. Line Down",
+    ["BRAILLE LINE:  '  $l'",
+     "     VISIBLE:  '  $l', cursor=1",
+     "SPEECH OUTPUT: 'blank'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Down",
+    ["BRAILLE LINE:  'Line 3'",
+     "     VISIBLE:  'Line 3', cursor=1",
+     "SPEECH OUTPUT: 'Line 3'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "8. Line Up",
+    ["BRAILLE LINE:  '  $l'",
+     "     VISIBLE:  '  $l', cursor=1",
+     "SPEECH OUTPUT: 'blank'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "9. Line Up",
+    ["BRAILLE LINE:  'No abbreviation here either.'",
+     "     VISIBLE:  'No abbreviation here either.', cursor=1",
+     "SPEECH OUTPUT: 'No abbreviation here either.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "10. Line Up",
+    ["BRAILLE LINE:  'HTML5 in 2004.'",
+     "     VISIBLE:  'HTML5 in 2004.', cursor=1",
+     "SPEECH OUTPUT: 'HTML5 in 2004.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "11. Line Up",
+    ["BRAILLE LINE:  'WHATWG started working on'",
+     "     VISIBLE:  'WHATWG started working on', cursor=1",
+     "SPEECH OUTPUT: 'WHATWG'",
+     "SPEECH OUTPUT: 'started working on'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "12. Line Up",
+    ["BRAILLE LINE:  'No abbreviation here.'",
+     "     VISIBLE:  'No abbreviation here.', cursor=1",
+     "SPEECH OUTPUT: 'No abbreviation here.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "13. Line Up",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()
diff --git a/test/keystrokes/firefox/line_nav_image_in_link.py 
b/test/keystrokes/firefox/line_nav_image_in_link.py
index 5aa4a38..34d1819 100644
--- a/test/keystrokes/firefox/line_nav_image_in_link.py
+++ b/test/keystrokes/firefox/line_nav_image_in_link.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_images_in_links.py 
b/test/keystrokes/firefox/line_nav_images_in_links.py
index 11101bb..e0b79e9 100644
--- a/test/keystrokes/firefox/line_nav_images_in_links.py
+++ b/test/keystrokes/firefox/line_nav_images_in_links.py
@@ -7,7 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
-sequence.append(PauseAction(3000))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(KeyComboAction("Down"))
 
diff --git a/test/keystrokes/firefox/line_nav_link_position_relative_on_focus.py 
b/test/keystrokes/firefox/line_nav_link_position_relative_on_focus.py
index 76c3575..5d3320b 100644
--- a/test/keystrokes/firefox/line_nav_link_position_relative_on_focus.py
+++ b/test/keystrokes/firefox/line_nav_link_position_relative_on_focus.py
@@ -5,6 +5,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_lists.py b/test/keystrokes/firefox/line_nav_lists.py
index 033605c..6e94a32 100644
--- a/test/keystrokes/firefox/line_nav_lists.py
+++ b/test/keystrokes/firefox/line_nav_lists.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_multi_line_text.py 
b/test/keystrokes/firefox/line_nav_multi_line_text.py
index 666664f..975b0b8 100644
--- a/test/keystrokes/firefox/line_nav_multi_line_text.py
+++ b/test/keystrokes/firefox/line_nav_multi_line_text.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_nested_tables.py 
b/test/keystrokes/firefox/line_nav_nested_tables.py
index f48580e..1af17a0 100644
--- a/test/keystrokes/firefox/line_nav_nested_tables.py
+++ b/test/keystrokes/firefox/line_nav_nested_tables.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_pre_lines.py b/test/keystrokes/firefox/line_nav_pre_lines.py
index 130ac01..eee861e 100644
--- a/test/keystrokes/firefox/line_nav_pre_lines.py
+++ b/test/keystrokes/firefox/line_nav_pre_lines.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_pre_links.py b/test/keystrokes/firefox/line_nav_pre_links.py
index 04c0a5a..edc038e 100644
--- a/test/keystrokes/firefox/line_nav_pre_links.py
+++ b/test/keystrokes/firefox/line_nav_pre_links.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_simple_form.py b/test/keystrokes/firefox/line_nav_simple_form.py
index 9991227..a6e5caf 100644
--- a/test/keystrokes/firefox/line_nav_simple_form.py
+++ b/test/keystrokes/firefox/line_nav_simple_form.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
@@ -53,17 +57,17 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "6. line Down",
-    ["BRAILLE LINE:  'I've recently taken up typing and plan  $l'",
+    ["BRAILLE LINE:  'I've recently taken up typing and plan to  $l'",
      "     VISIBLE:  'I've recently taken up typing an', cursor=1",
-     "SPEECH OUTPUT: 'I've recently taken up typing and plan '"]))
+     "SPEECH OUTPUT: 'I've recently taken up typing and plan to '"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "7. line Down",
-    ["BRAILLE LINE:  'to write my memoirs. $l'",
-     "     VISIBLE:  'to write my memoirs. $l', cursor=1",
-     "SPEECH OUTPUT: 'to write my memoirs.",
+    ["BRAILLE LINE:  'write my memoirs. $l'",
+     "     VISIBLE:  'write my memoirs. $l', cursor=1",
+     "SPEECH OUTPUT: 'write my memoirs.",
      "'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -182,18 +186,18 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "21. line Up",
-    ["BRAILLE LINE:  'to write my memoirs. $l'",
-     "     VISIBLE:  'to write my memoirs. $l', cursor=1",
-     "SPEECH OUTPUT: 'to write my memoirs.",
+    ["BRAILLE LINE:  'write my memoirs. $l'",
+     "     VISIBLE:  'write my memoirs. $l', cursor=1",
+     "SPEECH OUTPUT: 'write my memoirs.",
      "'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "22. line Up",
-    ["BRAILLE LINE:  'I've recently taken up typing and plan  $l'",
+    ["BRAILLE LINE:  'I've recently taken up typing and plan to  $l'",
      "     VISIBLE:  'I've recently taken up typing an', cursor=1",
-     "SPEECH OUTPUT: 'I've recently taken up typing and plan '"]))
+     "SPEECH OUTPUT: 'I've recently taken up typing and plan to '"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/line_nav_slash_test.py b/test/keystrokes/firefox/line_nav_slash_test.py
index c5e3f14..12680ec 100644
--- a/test/keystrokes/firefox/line_nav_slash_test.py
+++ b/test/keystrokes/firefox/line_nav_slash_test.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/line_nav_sun_java.py b/test/keystrokes/firefox/line_nav_sun_java.py
index 48fb9f6..4993308 100644
--- a/test/keystrokes/firefox/line_nav_sun_java.py
+++ b/test/keystrokes/firefox/line_nav_sun_java.py
@@ -7,7 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
-sequence.append(PauseAction(3000))
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(KeyComboAction("Down"))
 
diff --git a/test/keystrokes/firefox/line_nav_table_cell_links.py 
b/test/keystrokes/firefox/line_nav_table_cell_links.py
index 50f2217..acd9d0e 100644
--- a/test/keystrokes/firefox/line_nav_table_cell_links.py
+++ b/test/keystrokes/firefox/line_nav_table_cell_links.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/line_nav_textarea_last_line.params 
b/test/keystrokes/firefox/line_nav_textarea_last_line.params
new file mode 100644
index 0000000..c571fac
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_textarea_last_line.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/textarea.html
diff --git a/test/keystrokes/firefox/line_nav_textarea_last_line.py 
b/test/keystrokes/firefox/line_nav_textarea_last_line.py
new file mode 100644
index 0000000..553a2ef
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_textarea_last_line.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+"""Test of line navigation."""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
+sequence.append(KeyComboAction("Tab"))
+sequence.append(TypeAction("hello world"))
+sequence.append(KeyComboAction("Return"))
+sequence.append(TypeAction("goodbye world"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Up",
+    ["BRAILLE LINE:  'Label hello world $l'",
+     "     VISIBLE:  'Label hello world $l', cursor=18",
+     "SPEECH OUTPUT: 'hello world'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Down",
+    ["BRAILLE LINE:  'Label goodbye world $l'",
+     "     VISIBLE:  'Label goodbye world $l', cursor=20",
+     "SPEECH OUTPUT: 'goodbye world'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()
diff --git a/test/keystrokes/firefox/line_nav_wiki_down.py b/test/keystrokes/firefox/line_nav_wiki_down.py
index a5f781e..12c2c09 100644
--- a/test/keystrokes/firefox/line_nav_wiki_down.py
+++ b/test/keystrokes/firefox/line_nav_wiki_down.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(PauseAction(3000))
 sequence.append(KeyComboAction("Tab"))
 
diff --git a/test/keystrokes/firefox/line_nav_wiki_up.py b/test/keystrokes/firefox/line_nav_wiki_up.py
index 5ad80bb..668e9f3 100644
--- a/test/keystrokes/firefox/line_nav_wiki_up.py
+++ b/test/keystrokes/firefox/line_nav_wiki_up.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(PauseAction(3000))
 sequence.append(KeyComboAction("Tab"))
 
diff --git a/test/keystrokes/firefox/longdesc_1.py b/test/keystrokes/firefox/longdesc_1.py
index e7f041d..19ed2b8 100644
--- a/test/keystrokes/firefox/longdesc_1.py
+++ b/test/keystrokes/firefox/longdesc_1.py
@@ -10,7 +10,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
     ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -24,9 +24,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
+     "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/longdesc_11.py b/test/keystrokes/firefox/longdesc_11.py
index 3043e0c..b69607b 100644
--- a/test/keystrokes/firefox/longdesc_11.py
+++ b/test/keystrokes/firefox/longdesc_11.py
@@ -9,8 +9,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
-    ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+    ["KNOWN ISSUE: We don't know the longdesc is there due to 
https://bugzilla.mozilla.org/show_bug.cgi?id=1165433";,
+     "BRAILLE LINE:  'the image image'",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -23,10 +24,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
-    ["KNOWN ISSUE: This test fails not because of longdesc, but because jumping to any anchor in a page is 
broken",
-     "BRAILLE LINE:  'Fail if you land here h1'",
-     "     VISIBLE:  'Fail if you land here h1', cursor=1",
-     "SPEECH OUTPUT: 'heading level 1 Fail if you land here'"]))
+    ["BRAILLE LINE:  'Pass h1'",
+     "     VISIBLE:  'Pass h1', cursor=1",
+     "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
 sequence.start()
diff --git a/test/keystrokes/firefox/longdesc_12.py b/test/keystrokes/firefox/longdesc_12.py
index c4c3484..28f2897 100644
--- a/test/keystrokes/firefox/longdesc_12.py
+++ b/test/keystrokes/firefox/longdesc_12.py
@@ -11,8 +11,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
-    ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+    ["KNOWN ISSUE: We don't know the longdesc is there due to 
https://bugzilla.mozilla.org/show_bug.cgi?id=1165433";,
+     "BRAILLE LINE:  'the image image'",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
diff --git a/test/keystrokes/firefox/longdesc_13.py b/test/keystrokes/firefox/longdesc_13.py
index 8d3af15..79bffc4 100644
--- a/test/keystrokes/firefox/longdesc_13.py
+++ b/test/keystrokes/firefox/longdesc_13.py
@@ -31,10 +31,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "3. Having selected View Description, do a Where Am I for new location",
-    ["KNOWN ISSUE: Braille and eyeballs suggest we're in the right place. Speech does not. The test case 
states the image is broken.",
-     "BRAILLE LINE:  'Pass h1'",
+    ["BRAILLE LINE:  'Pass h1'",
      "     VISIBLE:  'Pass h1', cursor=1",
-     "SPEECH OUTPUT: 'the image invalid'"]))
+     "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
 sequence.start()
diff --git a/test/keystrokes/firefox/longdesc_14.py b/test/keystrokes/firefox/longdesc_14.py
index e7f041d..19ed2b8 100644
--- a/test/keystrokes/firefox/longdesc_14.py
+++ b/test/keystrokes/firefox/longdesc_14.py
@@ -10,7 +10,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
     ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -24,9 +24,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
+     "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/longdesc_15.py b/test/keystrokes/firefox/longdesc_15.py
index e7f041d..19ed2b8 100644
--- a/test/keystrokes/firefox/longdesc_15.py
+++ b/test/keystrokes/firefox/longdesc_15.py
@@ -10,7 +10,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
     ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -24,9 +24,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
+     "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/longdesc_2.py b/test/keystrokes/firefox/longdesc_2.py
index e7f041d..19ed2b8 100644
--- a/test/keystrokes/firefox/longdesc_2.py
+++ b/test/keystrokes/firefox/longdesc_2.py
@@ -10,7 +10,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
     ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -24,9 +24,7 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
+     "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/longdesc_3.py b/test/keystrokes/firefox/longdesc_3.py
index 3043e0c..5fe5b33 100644
--- a/test/keystrokes/firefox/longdesc_3.py
+++ b/test/keystrokes/firefox/longdesc_3.py
@@ -23,10 +23,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
-    ["KNOWN ISSUE: This test fails not because of longdesc, but because jumping to any anchor in a page is 
broken",
-     "BRAILLE LINE:  'Fail if you land here h1'",
-     "     VISIBLE:  'Fail if you land here h1', cursor=1",
-     "SPEECH OUTPUT: 'heading level 1 Fail if you land here'"]))
+    ["BRAILLE LINE:  'Pass h1'",
+     "     VISIBLE:  'Pass h1', cursor=1",
+     "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
 sequence.append(utils.AssertionSummaryAction())
 sequence.start()
diff --git a/test/keystrokes/firefox/longdesc_7.py b/test/keystrokes/firefox/longdesc_7.py
index f668a93..5fe5b33 100644
--- a/test/keystrokes/firefox/longdesc_7.py
+++ b/test/keystrokes/firefox/longdesc_7.py
@@ -24,8 +24,6 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
      "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
diff --git a/test/keystrokes/firefox/longdesc_8.py b/test/keystrokes/firefox/longdesc_8.py
index f668a93..b69607b 100644
--- a/test/keystrokes/firefox/longdesc_8.py
+++ b/test/keystrokes/firefox/longdesc_8.py
@@ -9,8 +9,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "1. Where Am I on image",
-    ["BRAILLE LINE:  'the image image'",
-     "     VISIBLE:  'the image image', cursor=(0|1)",
+    ["KNOWN ISSUE: We don't know the longdesc is there due to 
https://bugzilla.mozilla.org/show_bug.cgi?id=1165433";,
+     "BRAILLE LINE:  'the image image'",
+     "     VISIBLE:  'the image image', cursor=1",
      "SPEECH OUTPUT: 'the image image has long description'"]))
 
 sequence.append(PauseAction(3000))
@@ -24,8 +25,6 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
      "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
diff --git a/test/keystrokes/firefox/longdesc_9.py b/test/keystrokes/firefox/longdesc_9.py
index f668a93..5fe5b33 100644
--- a/test/keystrokes/firefox/longdesc_9.py
+++ b/test/keystrokes/firefox/longdesc_9.py
@@ -24,8 +24,6 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Having selected View Description, do a Where Am I for new location",
     ["BRAILLE LINE:  'Pass h1'",
-     "     VISIBLE:  'Pass h1', cursor=0",
-     "BRAILLE LINE:  'Pass h1'",
      "     VISIBLE:  'Pass h1', cursor=1",
      "SPEECH OUTPUT: 'heading level 1 Pass'"]))
 
diff --git a/test/keystrokes/firefox/object_nav_descriptions_down.py 
b/test/keystrokes/firefox/object_nav_descriptions_down.py
index 4b2aab8..ba059c5 100644
--- a/test/keystrokes/firefox/object_nav_descriptions_down.py
+++ b/test/keystrokes/firefox/object_nav_descriptions_down.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/object_nav_descriptions_up.py 
b/test/keystrokes/firefox/object_nav_descriptions_up.py
index 372d864..e287b06 100644
--- a/test/keystrokes/firefox/object_nav_descriptions_up.py
+++ b/test/keystrokes/firefox/object_nav_descriptions_up.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>End"))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/object_nav_simple_form_down.py 
b/test/keystrokes/firefox/object_nav_simple_form_down.py
index 24fd3dc..6485019 100644
--- a/test/keystrokes/firefox/object_nav_simple_form_down.py
+++ b/test/keystrokes/firefox/object_nav_simple_form_down.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
@@ -23,6 +27,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  ' $l', cursor=1",
      "SPEECH OUTPUT: 'Type something here: entry"]))
 
+sequence.append(PauseAction(1000))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
@@ -85,17 +91,17 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "10. line Down",
-    ["BRAILLE LINE:  'I've recently taken up typing and plan  $l'",
+    ["BRAILLE LINE:  'I've recently taken up typing and plan to  $l'",
      "     VISIBLE:  'I've recently taken up typing an', cursor=1",
-     "SPEECH OUTPUT: 'I've recently taken up typing and plan "]))
+     "SPEECH OUTPUT: 'I've recently taken up typing and plan to '"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "11. line Down",
-    ["BRAILLE LINE:  'to write my memoirs. $l'",
-     "     VISIBLE:  'to write my memoirs. $l', cursor=1",
-     "SPEECH OUTPUT: 'to write my memoirs.",
+    ["BRAILLE LINE:  'write my memoirs. $l'",
+     "     VISIBLE:  'write my memoirs. $l', cursor=1",
+     "SPEECH OUTPUT: 'write my memoirs.",
      "'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/object_nav_simple_form_up.py 
b/test/keystrokes/firefox/object_nav_simple_form_up.py
index 6b1bce9..1c5790d 100644
--- a/test/keystrokes/firefox/object_nav_simple_form_up.py
+++ b/test/keystrokes/firefox/object_nav_simple_form_up.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>End"))
 sequence.append(utils.AssertPresentationAction(
@@ -155,18 +159,18 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "19. line Up",
-    ["BRAILLE LINE:  'to write my memoirs. $l'",
-     "     VISIBLE:  'to write my memoirs. $l', cursor=1",
-     "SPEECH OUTPUT: 'to write my memoirs.",
+    ["BRAILLE LINE:  'write my memoirs. $l'",
+     "     VISIBLE:  'write my memoirs. $l', cursor=1",
+     "SPEECH OUTPUT: 'write my memoirs.",
      "'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "20. line Up",
-    ["BRAILLE LINE:  'I've recently taken up typing and plan  $l'",
+    ["BRAILLE LINE:  'I've recently taken up typing and plan to  $l'",
      "     VISIBLE:  'I've recently taken up typing an', cursor=1",
-     "SPEECH OUTPUT: 'I've recently taken up typing and plan "]))
+     "SPEECH OUTPUT: 'I've recently taken up typing and plan to '"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/say_all_entries.py b/test/keystrokes/firefox/say_all_entries.py
index de25a83..101a029 100644
--- a/test/keystrokes/firefox/say_all_entries.py
+++ b/test/keystrokes/firefox/say_all_entries.py
@@ -29,8 +29,8 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: '.'",
      "SPEECH OUTPUT: 'I'm a label'",
      "SPEECH OUTPUT: 'entry'",
-     "SPEECH OUTPUT: 'Am I a label as well?'",
      "SPEECH OUTPUT: 'entry'",
+     "SPEECH OUTPUT: 'Am I a label as well?'",
      "SPEECH OUTPUT: 'What the heck should we do here?'",
      "SPEECH OUTPUT: 'heading level 2'",
      "SPEECH OUTPUT: 'Looking at what follows visually, I'm not sure what I would type/i.e.'",
diff --git a/test/keystrokes/firefox/say_all_multi_line_text.py 
b/test/keystrokes/firefox/say_all_multi_line_text.py
index f072108..fe9ffb3 100644
--- a/test/keystrokes/firefox/say_all_multi_line_text.py
+++ b/test/keystrokes/firefox/say_all_multi_line_text.py
@@ -7,6 +7,8 @@ import utils
 
 sequence = MacroSequence()
 
+sequence.append(KeyComboAction("<Control>Home"))
+
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Add"))
 sequence.append(utils.AssertPresentationAction(
diff --git a/test/keystrokes/firefox/say_all_simple_form.py b/test/keystrokes/firefox/say_all_simple_form.py
index fd84b54..45a207e 100644
--- a/test/keystrokes/firefox/say_all_simple_form.py
+++ b/test/keystrokes/firefox/say_all_simple_form.py
@@ -13,13 +13,11 @@ sequence.append(utils.AssertPresentationAction(
     "1. KP_Add to do a SayAll",
     ["SPEECH OUTPUT: 'Type something here:'",
      "SPEECH OUTPUT: 'entry'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Magic disappearing text trick:'",
      "SPEECH OUTPUT: 'entry'",
      "SPEECH OUTPUT: 'tab to me and I disappear'",
      "SPEECH OUTPUT: 'Tell me a secret:'",
      "SPEECH OUTPUT: 'password text'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tell me a little more about yourself:'",
      "SPEECH OUTPUT: 'entry'",
      "SPEECH OUTPUT: 'I am a monkey with a long tail.  I like to swing from trees and eat bananas.  I've 
recently taken up typing and plan to write my memoirs.",
@@ -38,9 +36,9 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'Water'",
      "SPEECH OUTPUT: 'combo box'",
      "SPEECH OUTPUT: 'Which sports do you like?'",
-     "SPEECH OUTPUT: 'Hockey'",
-     "SPEECH OUTPUT: 'multi-select'",
-     "SPEECH OUTPUT: 'List with 4 items'",
+#     "SPEECH OUTPUT: 'Hockey'",
+#     "SPEECH OUTPUT: 'multi-select'",
+#     "SPEECH OUTPUT: 'List with 4 items'",
      "SPEECH OUTPUT: 'Dashing picture of Willie Walker'",
      "SPEECH OUTPUT: 'image'",
      "SPEECH OUTPUT: 'Ain't he handsome (please say yes)?'",
diff --git a/test/keystrokes/firefox/spelling_errors.py b/test/keystrokes/firefox/spelling_errors.py
index 3661d0c..e5bc582 100644
--- a/test/keystrokes/firefox/spelling_errors.py
+++ b/test/keystrokes/firefox/spelling_errors.py
@@ -303,7 +303,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
 sequence.append(utils.AssertPresentationAction(
     "36. Right",
-    []))
+    ["BRAILLE LINE:  'Thiss is a tesst.  $l'",
+     "     VISIBLE:  'Thiss is a tesst.  $l', cursor=19",
+     "SPEECH OUTPUT: 'blank' voice=system"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Left"))
diff --git a/test/keystrokes/firefox/ui_doc_tabs.py b/test/keystrokes/firefox/ui_doc_tabs.py
index f0bb962..3325b60 100644
--- a/test/keystrokes/firefox/ui_doc_tabs.py
+++ b/test/keystrokes/firefox/ui_doc_tabs.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(PauseAction(3000))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/ui_role_accel_label.py b/test/keystrokes/firefox/ui_role_accel_label.py
index 67add73..4e292a9 100644
--- a/test/keystrokes/firefox/ui_role_accel_label.py
+++ b/test/keystrokes/firefox/ui_role_accel_label.py
@@ -32,7 +32,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'Firefox application Mozilla Firefox frame Menu Bar tool bar Application menu bar New 
Private Window(Shift+Ctrl+P)'",
      "     VISIBLE:  'New Private Window(Shift+Ctrl+P)', cursor=1",
      "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: 'Menu Bar tool bar New Private Window Shift+Ctrl+P 3 of 12.'",
+     "SPEECH OUTPUT: 'Menu Bar tool bar menu bar New Private Window Shift+Ctrl+P 3 of 12.'",
      "SPEECH OUTPUT: 'W'"]))
 
 sequence.append(utils.AssertionSummaryAction())
diff --git a/test/keystrokes/firefox/ui_role_list_item.py b/test/keystrokes/firefox/ui_role_list_item.py
index 9975f93..8f4db08 100644
--- a/test/keystrokes/firefox/ui_role_list_item.py
+++ b/test/keystrokes/firefox/ui_role_list_item.py
@@ -15,9 +15,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
 sequence.append(utils.AssertPresentationAction(
     "1. Right Arrow in list",
-    ["BRAILLE LINE:  'Firefox application Firefox Preferences dialog Tabs list box General'",
-     "     VISIBLE:  'General', cursor=1",
-     "BRAILLE LINE:  'Firefox application Firefox Preferences dialog Tabs list box Tabs'",
+    ["BRAILLE LINE:  'Firefox application Firefox Preferences dialog Tabs list box Tabs'",
      "     VISIBLE:  'Tabs', cursor=1",
      "SPEECH OUTPUT: 'Tabs'"]))
 
@@ -25,9 +23,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
 sequence.append(utils.AssertPresentationAction(
     "2. Left Arrow in list",
-    ["BRAILLE LINE:  'Firefox application Firefox Preferences dialog General list box Tabs'",
-     "     VISIBLE:  'Tabs', cursor=1",
-     "BRAILLE LINE:  'Firefox application Firefox Preferences dialog General list box General'",
+    ["BRAILLE LINE:  'Firefox application Firefox Preferences dialog General list box General'",
      "     VISIBLE:  'General', cursor=1",
      "SPEECH OUTPUT: 'General'"]))
 
@@ -37,7 +33,7 @@ sequence.append(utils.AssertPresentationAction(
     "3. Basic Where Am I",
     ["BRAILLE LINE:  'Firefox application Firefox Preferences dialog General list box General'",
      "     VISIBLE:  'General', cursor=1",
-     "SPEECH OUTPUT: 'list item General 1 of 8'"]))
+     "SPEECH OUTPUT: 'list item General 1 of 9'"]))
 
 sequence.append(KeyComboAction("Escape"))
 
diff --git a/test/keystrokes/firefox/ui_role_radio_button.py b/test/keystrokes/firefox/ui_role_radio_button.py
index 9c86cdf..9f54c33 100644
--- a/test/keystrokes/firefox/ui_role_radio_button.py
+++ b/test/keystrokes/firefox/ui_role_radio_button.py
@@ -14,7 +14,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Alt>a"))
 sequence.append(utils.AssertPresentationAction(
     "1. Alt a to radio button group",
-    ["BRAILLE LINE:  'Firefox application Print dialog General page tab &=y All Pages radio button'",
+    ["BRAILLE LINE:  'Firefox application Print dialog General page tab Range Range &=y All Pages radio 
button'",
      "     VISIBLE:  '&=y All Pages radio button', cursor=1",
      "SPEECH OUTPUT: 'General page tab'",
      "SPEECH OUTPUT: 'All Pages selected radio button'"]))
@@ -23,7 +23,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Basic Where Am I",
-    ["BRAILLE LINE:  'Firefox application Print dialog General page tab &=y All Pages radio button'",
+    ["BRAILLE LINE:  'Firefox application Print dialog General page tab Range Range &=y All Pages radio 
button'",
      "     VISIBLE:  '&=y All Pages radio button', cursor=1",
      "SPEECH OUTPUT: 'All Pages radio button selected 1 of 4.'",
      "SPEECH OUTPUT: 'Alt+A'"]))
diff --git a/test/keystrokes/firefox/ui_role_tree.py b/test/keystrokes/firefox/ui_role_tree.py
index c39ce21..08c90a1 100644
--- a/test/keystrokes/firefox/ui_role_tree.py
+++ b/test/keystrokes/firefox/ui_role_tree.py
@@ -110,7 +110,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "13. Tab back to tree table",
-    ["BRAILLE LINE:  'Firefox application Library frame tree table Tags column header Bookmarks Toolbar   
table row TREE LEVEL 1'",
+    ["BRAILLE LINE:  'Firefox application Library frame tree table Bookmarks Toolbar   table row TREE LEVEL 
1'",
      "     VISIBLE:  'Bookmarks Toolbar   table row TR', cursor=1",
      "SPEECH OUTPUT: 'Bookmarks Toolbar   table row'"]))
 
diff --git a/test/keystrokes/firefox/ui_role_tree_table.py b/test/keystrokes/firefox/ui_role_tree_table.py
index d6f3667..1bf105f 100644
--- a/test/keystrokes/firefox/ui_role_tree_table.py
+++ b/test/keystrokes/firefox/ui_role_tree_table.py
@@ -14,7 +14,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "1. Down Arrow in tree table",
-    ["BRAILLE LINE:  'Firefox application Library frame tree table Location column header Bookmarks Menu   
table row TREE LEVEL 1'",
+    ["BRAILLE LINE:  'Firefox application Library frame tree table Bookmarks Menu   table row TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Menu   table row TREE ', cursor=1",
      "SPEECH OUTPUT: 'Bookmarks Menu   table row'"]))
 
@@ -22,7 +22,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(utils.AssertPresentationAction(
     "2. Basic Where Am I",
-    ["BRAILLE LINE:  'Firefox application Library frame tree table Location column header Bookmarks Menu   
table row TREE LEVEL 1'",
+    ["BRAILLE LINE:  'Firefox application Library frame tree table Bookmarks Menu   table row TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Menu   table row TREE ', cursor=1",
      "SPEECH OUTPUT: 'Bookmarks Menu   table row'"]))
 
@@ -30,7 +30,7 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "3. Up Arrow in tree table",
-    ["BRAILLE LINE:  'Firefox application Library frame tree table Tags column header Bookmarks Toolbar   
table row TREE LEVEL 1'",
+    ["BRAILLE LINE:  'Firefox application Library frame tree table Bookmarks Toolbar   table row TREE LEVEL 
1'",
      "     VISIBLE:  'Bookmarks Toolbar   table row TR', cursor=1",
      "SPEECH OUTPUT: 'Bookmarks Toolbar   table row'"]))
 
diff --git a/test/keystrokes/firefox/word_nav_links.py b/test/keystrokes/firefox/word_nav_links.py
index 0f5a010..05ed199 100644
--- a/test/keystrokes/firefox/word_nav_links.py
+++ b/test/keystrokes/firefox/word_nav_links.py
@@ -7,6 +7,10 @@ import utils
 
 sequence = MacroSequence()
 
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(KeyComboAction("Down"))
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]