Index: src/mlx/acft.py
===================================================================
--- src/mlx/acft.py	(revision 345)
+++ src/mlx/acft.py	(revision 349)
@@ -137,6 +137,6 @@
         self._checkers.append(checks.PayloadChecker())
 
-        self._checkers.append(checks.SpeedChecker())
-        #self._checkers.append(checks.NoStrobeSpeedChecker())
+        #self._checkers.append(checks.SpeedChecker())
+        self._checkers.append(checks.NoStrobeSpeedChecker())
         self._checkers.append(checks.VSChecker())
 
Index: src/mlx/checks.py
===================================================================
--- src/mlx/checks.py	(revision 346)
+++ src/mlx/checks.py	(revision 349)
@@ -1285,13 +1285,15 @@
     """Check if the speed is in the prescribed limits."""
     @staticmethod
-    def logSpeedFault(flight, state):
+    def logSpeedFault(flight, state, stage = None, updateID = None):
         """Log the speed fault."""
         message = "Taxi speed over %.0f %s" % \
                   (flight.speedFromKnots(50), flight.getEnglishSpeedUnit())
-        flight.handleFault((SpeedChecker, flight.stage), state.timestamp,
-                           FaultChecker._appendDuring(flight, message),
-                           FaultChecker._getLinearScore(50, 80, 10, 15,
-                                                        state.groundSpeed),
-                           updatePrevious = True)
+        if stage is None:
+            stage = flight.stage
+        score = FaultChecker._getLinearScore(50, 80, 10, 15, state.groundSpeed)
+        return flight.handleFault((SpeedChecker, stage), state.timestamp,
+                                  FaultChecker._appendDuring(flight, message),
+                                  score, updatePrevious = updateID is None,
+                                  updateID = updateID)
 
     def isCondition(self, flight, aircraft, oldState, state):
@@ -1314,5 +1316,6 @@
     saved as a provisional takeoff state. If the speed then decreases below 50
     knots, or the plane remains on the ground for more than 20 seconds, a taxi
-    speed error is logged with the highest ground speed detected.
+    speed error is logged with the highest ground speed detected. This state is
+    also stored in the flight object as a possible
 
     If the plane becomes airborne within 20 seconds, the stage becomes TAKEOFF,
@@ -1345,10 +1348,10 @@
 
                 if state.timestamp > (self._takeoffState.timestamp + 20):
-                    SpeedChecker.logSpeedFault(flight, self._highestSpeedState)
+                    flight.setRTOState(self._highestSpeedState)
                 elif not state.onTheGround:
                     aircraft.setStage(self._takeoffState, const.STAGE_TAKEOFF)
                     self._takeoffState = None
         elif self._takeoffState is not None:
-            SpeedChecker.logSpeedFault(flight, self._highestSpeedState)
+            flight.setRTOState(self._highestSpeedState)
             self._takeoffState = None
 
Index: src/mlx/flight.py
===================================================================
--- src/mlx/flight.py	(revision 348)
+++ src/mlx/flight.py	(revision 349)
@@ -1,4 +1,5 @@
 
 from soundsched import SoundScheduler, ChecklistScheduler
+from checks import SpeedChecker
 
 import const
@@ -45,4 +46,7 @@
         self.blockTimeEnd = None
 
+        self._rtoState = None
+        self._rtoLogEntryID = None
+
         self._lastDistanceTime = None
         self._previousLatitude = None
@@ -229,4 +233,14 @@
         return self.aircraft.speedInKnots if self.aircraft is not None \
                else True
+
+    @property
+    def hasRTO(self):
+        """Determine if we have an RTO state."""
+        return self._rtoState is not None
+
+    @property
+    def rtoState(self):
+        """Get the RTO state."""
+        return self._rtoState
 
     def handleState(self, oldState, currentState):
@@ -270,5 +284,5 @@
 
     def handleFault(self, faultID, timestamp, what, score,
-                    updatePrevious = False):
+                    updatePrevious = False, updateID = None):
         """Handle the given fault.
 
@@ -277,7 +291,9 @@
         the score is greater than last time. This ID can be, e.g. the checker
         the report comes from."""
-        self.logger.fault(faultID, timestamp, what, score,
-                          updatePrevious = updatePrevious)
+        id = self.logger.fault(faultID, timestamp, what, score,
+                               updatePrevious = updatePrevious,
+                               updateID = updateID)
         self._gui.setRating(self.logger.getRating())
+        return id
 
     def handleNoGo(self, faultID, timestamp, what, shortReason):
@@ -285,4 +301,32 @@
         self.logger.noGo(faultID, timestamp, what)
         self._gui.setNoGo(shortReason)
+
+    def setRTOState(self, state):
+        """Set the state that might be used as the RTO state.
+
+        If there has been no RTO state, the GUI is notified that from now on
+        the user may select to report an RTO."""
+        hadNoRTOState = self._rtoState is None
+
+        self._rtoState = state
+        self._rtoLogEntryID = \
+            SpeedChecker.logSpeedFault(self, state,
+                                       stage = const.STAGE_PUSHANDTAXI)
+
+        if hadNoRTOState:
+            self._gui.updateRTO()
+
+    def rtoToggled(self, indicated):
+        """Called when the user has toggled the RTO indication."""
+        if self._rtoState is not None:
+            if indicated:
+                self.logger.clearFault(self._rtoLogEntryID,
+                                       "RTO at %d knots" %
+                                       (self._rtoState.groundSpeed,))
+                self._gui.setRating(self.logger.getRating())
+            else:
+                SpeedChecker.logSpeedFault(self, self._rtoState,
+                                           stage = const.STAGE_PUSHANDTAXI,
+                                           updateID = self._rtoLogEntryID)
 
     def flareStarted(self, flareStart, flareStartFS):
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 347)
+++ src/mlx/gui/flight.py	(revision 349)
@@ -2007,5 +2007,5 @@
                                   xscale = 0.0, yscale = 0.0)
 
-        table = gtk.Table(5, 4)
+        table = gtk.Table(6, 4)
         table.set_row_spacings(4)
         table.set_col_spacings(16)
@@ -2086,4 +2086,10 @@
         table.attach(self._v2Unit, 3, 4, 4, 5)
 
+        self._rto = gtk.CheckButton(xstr("takeoff_rto"))
+        self._rto.set_use_underline(True)
+        self._rto.set_tooltip_text(xstr("takeoff_rto_tooltip"))
+        self._rto.connect("toggled", self._rtoToggled)
+        table.attach(self._rto, 2, 4, 5, 6, ypadding = 8)
+
         self.addCancelFlightButton()
 
@@ -2116,4 +2122,9 @@
         """Get the v2 speed."""
         return self._v2.get_int()
+
+    @property
+    def rtoIndicated(self):
+        """Get whether the pilot has indicated if there was an RTO."""
+        return self._rto.get_active()
 
     def activate(self):
@@ -2140,4 +2151,7 @@
         self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip" + i18nSpeedUnit))
 
+        self._rto.set_active(False)
+        self._rto.set_sensitive(False)
+
         self._button.set_sensitive(False)
         self._forwardAllowed = False
@@ -2154,4 +2168,10 @@
         self._vr.reset()
         self._v2.reset()
+
+    def setRTOEnabled(self, enabled):
+        """Set the RTO checkbox enabled or disabled."""
+        if not enabled:
+            self._rto.set_active(False)
+        self._rto.set_sensitive(enabled)
 
     def _updateForwardButton(self):
@@ -2176,4 +2196,8 @@
         entry.set_text(entry.get_text().upper())
         self._valueChanged(entry, arg)
+
+    def _rtoToggled(self, button):
+        """Called when the RTO check button is toggled."""
+        self._wizard.rtoToggled(button.get_active())
 
     def _backClicked(self, button):
@@ -2971,4 +2995,9 @@
         """Get the V2 speed."""
         return self._takeoffPage.v2
+
+    @property
+    def rtoIndicated(self):
+        """Get whether the pilot has indicated that an RTO has occured."""
+        return self._takeoffPage.rtoIndicated
 
     @property
@@ -3162,4 +3191,18 @@
                              callback = callback)
 
+    def updateRTO(self):
+        """Update the RTO state.
+
+        The RTO checkbox will be enabled if the flight has an RTO state and the
+        comments field contains some text."""
+        flight = self.gui.flight
+        rtoEnabled = flight is not None and flight.hasRTO and \
+                     self.gui.hasComments
+        self._takeoffPage.setRTOEnabled(rtoEnabled)
+
+    def rtoToggled(self, indicated):
+        """Called when the RTO indication has changed."""
+        self.gui.rtoToggled(indicated)
+
     def _connectSimulator(self):
         """Connect to the simulator."""
@@ -3179,3 +3222,2 @@
 
 #-----------------------------------------------------------------------------
-
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 345)
+++ src/mlx/gui/gui.py	(revision 349)
@@ -303,4 +303,9 @@
 
     @property
+    def rtoIndicated(self):
+        """Get whether the pilot has indicated than an RTO has occured."""
+        return self._wizard.rtoIndicated
+
+    @property
     def arrivalRunway(self):
         """Get the arrival runway."""
@@ -341,4 +346,9 @@
         """Get the comments."""
         return self._flightInfo.comments
+
+    @property
+    def hasComments(self):
+        """Indicate whether there is a comment."""
+        return self._flightInfo.hasComments
 
     @property
@@ -728,4 +738,15 @@
         else:
             callback(self._fleet)
+
+    def updateRTO(self, inLoop = False):
+        """Indicate that the RTO state should be updated."""
+        if inLoop:
+            self._wizard.updateRTO()
+        else:
+            gobject.idle_add(self.updateRTO, True)
+
+    def rtoToggled(self, indicated):
+        """Called when the user has toggled the RTO checkbox."""
+        self._flight.rtoToggled(indicated)
 
     def _fleetResultCallback(self, returned, result):
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 300)
+++ src/mlx/gui/info.py	(revision 349)
@@ -33,5 +33,5 @@
                  (const.DELAYCODE_WEATHER, xstr("info_delay_weather")),
                  (const.DELAYCODE_PERSONAL, xstr("info_delay_personal")) ]
-    
+
     @staticmethod
     def _createCommentArea(label):
@@ -50,5 +50,5 @@
         alignment.set_padding(padding_top = 4, padding_bottom = 4,
                               padding_left = 8, padding_right = 8)
-        
+
         scroller = gtk.ScrolledWindow()
         # FIXME: these should be constants
@@ -80,4 +80,5 @@
         (frame, self._comments) = FlightInfo._createCommentArea(xstr("info_comments"))
         commentsBox.pack_start(frame, True, True, 8)
+        self._comments.get_buffer().connect("changed", self._commentsChanged)
 
         (frame, self._flightDefects) = \
@@ -130,5 +131,10 @@
         return text2unicode(buffer.get_text(buffer.get_start_iter(),
                                             buffer.get_end_iter(), True))
-    
+
+    @property
+    def hasComments(self):
+        """Get whether there is any text in comments field."""
+        return self._comments.get_buffer().get_char_count()>0
+
     @property
     def flightDefects(self):
@@ -147,5 +153,5 @@
                 codes.append(delayCodes[index][0])
         return codes
-            
+
     def enable(self):
         """Enable the flight info tab."""
@@ -153,5 +159,5 @@
         self._flightDefects.set_sensitive(True)
         self._delayTable.set_sensitive(True)
-        
+
     def disable(self):
         """Enable the flight info tab."""
@@ -167,2 +173,6 @@
         for widget in self._delayCodeWidgets:
             widget.set_active(False)
+
+    def _commentsChanged(self, textbuffer):
+        """Called when the comments have changed."""
+        self._gui.updateRTO(inLoop = True)
Index: src/mlx/logger.py
===================================================================
--- src/mlx/logger.py	(revision 346)
+++ src/mlx/logger.py	(revision 349)
@@ -97,8 +97,6 @@
 
         def copy(self, timestamp = None, clearTimestamp = False, text = None,
-                 faultScore = None):
+                 faultID = None, faultScore = None, clearFault = False):
             """Create a copy of this entry with the given values changed."""
-            assert faultScore is None or self._faultID is not None
-
             return Logger.Entry(None if clearTimestamp
                                 else self._timestamp if timestamp is None
@@ -109,8 +107,12 @@
                                 showTimestamp = self._showTimestamp,
 
-                                faultID = self._faultID,
+                                faultID =
+                                None if clearFault
+                                else self._faultID if faultID is None
+                                else faultID,
 
                                 faultScore =
-                                self._faultScore if faultScore is None
+                                None if clearFault
+                                else self._faultScore if faultScore is None
                                 else faultScore,
 
@@ -248,5 +250,5 @@
 
     def fault(self, faultID, timestamp, what, score,
-              updatePrevious = False):
+              updatePrevious = False, updateID = None):
         """Report a fault.
 
@@ -262,4 +264,7 @@
         and the new score is not greater than the latest one, the ID of the
         latest one is returned.
+
+        If updateID is given, the log entry with the given ID will be
+        'upgraded' to be a fault with the given data.
 
         Returns an ID of the fault, or -1 if it was not logged."""
@@ -279,12 +284,19 @@
                                         faultScore = score)
             self._updateEntry(id, newEntry)
+        elif updateID is not None:
+            id = updateID
+            newEntry = self._entries[id].copy(timestamp = timestamp,
+                                              text = text, faultID = faultID,
+                                              faultScore = score)
+            self._updateEntry(id, newEntry)
         else:
             id = self._addEntry(Logger.Entry(timestamp, text, faultID = faultID,
                                              faultScore = score))
 
-        (messageType, duration) = (const.MESSAGETYPE_NOGO, 10) \
-                                  if score==Logger.NO_GO_SCORE \
-                                  else (const.MESSAGETYPE_FAULT, 5)
-        sendMessage(messageType, text, duration)
+        if updateID is None:
+            (messageType, duration) = (const.MESSAGETYPE_NOGO, 10) \
+                                      if score==Logger.NO_GO_SCORE \
+                                      else (const.MESSAGETYPE_FAULT, 5)
+            sendMessage(messageType, text, duration)
 
         return id
@@ -311,4 +323,10 @@
         self._updateEntry(id, self._entries[id].copy(text = line))
 
+    def clearFault(self, id, text):
+        """Update the line with the given ID to contain the given string,
+        and clear its fault state."""
+        newEntry = self._entries[id].copy(text = text, clearFault = True)
+        self._updateEntry(id, newEntry)
+
     def _addEntry(self, entry):
         """Add the given entry to the log.
