text: from __future__ import absolute_import, print_function, unicode_literals
  
  import sys
  import threading
  
  import halo.cursor as cursor
  
  from halo import Halo
  from halo._utils import colored_frame, decode_utf_8_text
  
  
  class HaloNotebook(Halo):
      def __init__(
          self,
          text="",
          color="cyan",
          text_color=None,
          spinner=None,
          placement="left",
          animation=None,
          interval=-1,
          enabled=True,
          stream=sys.stdout,
      ):
          super(HaloNotebook, self).__init__(
              text=text,
              color=color,
              text_color=text_color,
              spinner=spinner,
              placement=placement,
              animation=animation,
              interval=interval,
              enabled=enabled,
              stream=stream,
          )
          self.output = self._make_output_widget()
  
      def _make_output_widget(self):
          from ipywidgets.widgets import Output
  
          return Output()
  
      # TODO: using property and setter
      def _output(self, text=""):
          return ({"name": "stdout", "output_type": "stream", "text": text},)
  
      def clear(self):
          if not self.enabled:
              return self
  
          with self.output:
              self.output.outputs += self._output("\r")
              self.output.outputs += self._output(self.CLEAR_LINE)
  
          self.output.outputs = self._output()
          return self
  
      def _render_frame(self):
          frame = self.frame()
          output = "\r{}".format(frame)
          with self.output:
              self.output.outputs += self._output(output)
  
      def start(self, text=None):
          if text is not None:
              self.text = text
  
          if not self.enabled or self._spinner_id is not None:
              return self
  
          if self._stream.isatty():
              cursor.hide()
  
          self.output = self._make_output_widget()
          from IPython.display import display
  
          display(self.output)
          self._stop_spinner = threading.Event()
          self._spinner_thread = threading.Thread(target=self.render)
          self._spinner_thread.daemon = True
          self._render_frame()
          self._spinner_id = self._spinner_thread.name
          self._spinner_thread.start()
  
          return self
  
      def stop_and_persist(self, symbol=" ", text=None):
          """Stops the spinner and persists the final frame to be shown.
          Parameters
          ----------
          symbol : str, optional
              Symbol to be shown in final frame
          text: str, optional
              Text to be shown in final frame
  
          Returns
          -------
          self
          """
          if not self.enabled:
              return self
  
          symbol = decode_utf_8_text(symbol)
  
          if text is not None:
              text = decode_utf_8_text(text)
          else:
              text = self._text["original"]
  
          text = text.strip()
  
          if self._text_color:
              text = colored_frame(text, self._text_color)
  
          self.stop()
  
          output = "\r{} {}\n".format(
              *[(text, symbol) if self._placement == "right" else (symbol, text)][0]
          )
  
          with self.output:
              self.output.outputs = self._output(output)
  