docs: def _base_bar_handler(self, bar):
          """ non threaded bar handler (called by threaded _tick_handler) """
          # bar symbol
          symbol = bar['symbol'].values
          if len(symbol) == 0:
              return
          symbol = symbol[0]
          self_bars = self.bars.copy()  # work on copy
  
          is_tick_or_volume_bar = False
          handle_bar = True
  
          if self.resolution[-1] in ("S", "K", "V"):
              is_tick_or_volume_bar = True
              handle_bar = self._caller("_tick_handler")
  
          # drip is also ok
          handle_bar = handle_bar or self._caller("drip")
  
          if is_tick_or_volume_bar:
              # just add a bar (used by tick bar bandler)
              if self.threads == 0:
                  self.bars = self._update_window(self.bars, bar,
                                                  window=self.bar_window)
              else:
                  self_bars = self._update_window(self_bars, bar,
                                                  window=self.bar_window)
          else:
              # add the bar and resample to resolution
              if self.threads == 0:
                  self.bars = self._update_window(self.bars, bar,
                                                  window=self.bar_window,
                                                  resolution=self.resolution)
              else:
                  self_bars = self._update_window(self_bars, bar,
                                                  window=self.bar_window,
                                                  resolution=self.resolution)
  
          # assign new data to self.bars if threaded
          if self.threads > 0:
              self.bars = self._thread_safe_merge(symbol, self.bars, self_bars)
  
          # optimize pandas
          if len(self.bars) == 1:
              self.bars['symbol'] = self.bars['symbol'].astype('category')
              self.bars['symbol_group'] = self.bars['symbol_group'].astype('category')
              self.bars['asset_class'] = self.bars['asset_class'].astype('category')
  
          # new bar?
          hash_string = bar[:1]['symbol'].to_string().translate(
              str.maketrans({key: None for key in "\n -:+"}))
          this_bar_hash = abs(hash(hash_string)) % (10 ** 8)
  
          newbar = True
          if symbol in self.bar_hashes.keys():
              newbar = self.bar_hashes[symbol] != this_bar_hash
          self.bar_hashes[symbol] = this_bar_hash
  
          if newbar and handle_bar:
              if self.bars[(self.bars['symbol'] == symbol) | (
                      self.bars['symbol_group'] == symbol)].empty:
                  return
              bar_instrument = self.get_instrument(symbol)
              if bar_instrument:
                  self.record_ts = bar.index[0]
                  self.on_bar(bar_instrument)
                  # if self.resolution[-1] not in ("S", "K", "V"):
                  self.record(bar)