                                            timestamps_shape=timestamps.shape)
          else:
              self._add_latest_live(session_id, loss, timestamps)
  
      def _to_numpy(self, data, is_live):
          """ Extract each individual step data into separate numpy arrays for loss and timestamps.
  
          Timestamps are stored float64 as the extra accuracy is needed for correct timings. Arrays
          are returned at the length of the shortest available data (i.e. truncated records are
          dropped)
 
</s> remove         if not is_live or (is_live and not self._data.get(session_id, None)):
            self._data[session_id] = dict(labels=self._loss_labels,
                                          loss=zlib.compress(loss),
                                          loss_shape=loss.shape,
                                          timestamps=zlib.compress(timestamps),
                                          timestamps_shape=timestamps.shape)
 </s> add         if not is_live or (is_live and not self._data.get(session_id)):
            self._data[session_id] = _CacheData(self._loss_labels, timestamps, loss) </s> remove         dict
            The `session_id` (s) as key, the values are a dictionary containing the requested
            metric information for each session returned
 </s> add         dict or ``None``
            The `session_id`(s) as key, the values are a dictionary containing the requested
            metric information for each session returned. ``None`` if no data is stored for the
            given session_id </s> remove         times, loss = zip(*[(data[idx].get("timestamp"), data[idx].get("loss", []))
                            for idx in sorted(data)])
        times, loss = self._process_data(data, times, loss, is_live)
 </s> add         times, loss = self._process_data(data, is_live) </s> remove     def _get_log_filename(cls, folder, filenames):
 </s> add     def _get_log_filename(cls, folder: str, filenames: List[str]) -> str: </s> remove     def _process_data(self, data, timestamps, loss, is_live):
 </s> add     def _process_data(self,
                      data: Dict[int, EventData],
                      is_live: bool) -> Tuple[List[float], List[List[float]]]:
    def _to_numpy(self,
                  data: Dict[int, EventData],
                  is_live: bool) -> Tuple[np.ndarray, np.ndarray]:
                                            timestamps_shape=timestamps.shape)
          else:
              self._add_latest_live(session_id, loss, timestamps)
  
    def _to_numpy(self,
                  data: Dict[int, EventData],
                  is_live: bool) -> Tuple[np.ndarray, np.ndarray]:
          """ Extract each individual step data into separate numpy arrays for loss and timestamps.
  
          Timestamps are stored float64 as the extra accuracy is needed for correct timings. Arrays
          are returned at the length of the shortest available data (i.e. truncated records are
          dropped)
keep keep keep keep replace keep keep keep keep keep
 Bugfixes
  - plugin.train.unbalanced - decoder b
  - gui.stats - crash when log folder deleted
  - setup.py - install gcc=12.1.0 on linux (scipy dep)
  - setup.py - don't test ROCm unless valid
  - typofix - cli_args extract singleprocess help
typing
  - lib.gui.analysis.event_reader
  - lib.gpu_stats.directml - make platform specific
unit tests
  - lib.gui.analysis.event_reader 
lib/gui/analysis/event_reader.py