text: """
  HTML parser
  """
  import os
  import webbrowser
  import tkinter as tk
  from tkinter import font
  from copy import deepcopy
  from PIL import Image, ImageTk
  from html.parser import HTMLParser
  from collections import OrderedDict
  import requests
  from io import BytesIO
  
  #__________________________________________________________________________________________________
  class Defs():
      DEFAULT_TEXT_FONT_FAMILY = ("Segoe ui", "Calibri", "Helvetica", "TkTextFont")
      FONT_SIZE = 14
      PREFORMATTED_FONT_FAMILY = ("Courier", "DejaVu Sans Mono", "TkFixedFont")
      HEADINGS_FONT_SIZE = {
          'h1':32,
          'h2':24,
          'h3':18,
          'h4':16,
          'h5':13,
          'h6':10,
      }
  
  
  class HTML:
      #----------------------------------------------------------------------------------------------
      """
      List of supported HTML tags and attrs 
      """
      class Tag():
          BR = 'br'
          UL = 'ul'
          OL = 'ol'
          LI = 'li'
          IMG = 'img'
          A = 'a'
          B = 'b'
          STRONG = 'strong'
          I = 'i'
          EM = 'em'
          U = 'u'
          MARK = 'mark'
          SPAN = 'span'
          DIV = 'div'
          P = 'p'
          PRE = 'pre'
          CODE = 'code'
          H1 = 'h1'
          H2 = 'h2'
          H3 = 'h3'
          H4 = 'h4'
          H5 = 'h5'
          H6 = 'h6'
  
      class Attrs():
          STYLE = 'style'
          HREF ='href'
          SRC = 'src'
          WIDTH = 'width'
          HEIGHT = 'height'
          TYPE = 'type'
  
      class TypeOrderedList():
          _1 = '1'
          a = 'a'
          A = 'A'
  
      class Style():
          COLOR = 'color'
          BACKGROUND_COLOR = 'background-color'
          FONT_FAMILY = 'font-family'
          FONT_SIZE = 'font-size'
          TEXT_ALIGN = 'text-align'
          TEXT_DECORATION = 'text-decoration'
  
      class StyleTextDecoration():
          UNDERLINE = 'underline'
          LINE_THROUGH = 'line-through'
  
      HEADING_TAGS = (
          Tag.H1,
          Tag.H2,
          Tag.H3,
          Tag.H4,
          Tag.H5,
          Tag.H6,
      )
  
      TEXT_ALIGN_TAGS = HEADING_TAGS + (
          Tag.UL,
          Tag.OL,
          Tag.LI,
          Tag.DIV,
          Tag.P,
          Tag.PRE,
          Tag.CODE,
      ) 
  
      NEW_LINE_TAGS = HEADING_TAGS + (
          Tag.UL,
          Tag.OL,
          Tag.DIV,
          Tag.P,
          Tag.PRE,
          Tag.CODE,
      )  
  
      STYLE_TAGS = TEXT_ALIGN_TAGS + (
          Tag.A,
          Tag.B,
          Tag.STRONG,
          Tag.I,
          Tag.EM,
          Tag.U,
          Tag.MARK,
          Tag.SPAN,
      )
  
  
  
  #--------------------------------------------------------------------------------------------------
  # Text widget defs
  
  class WCfg():
      KEY = "config"
      BACKGROUND = "background"
      FOREGROUND = "foreground"
      JUSTIFY = "justify"
      TABS = "tabs"
  
  class Fnt():
      KEY = "font"
      FAMILY = "family"
      SIZE = "size"
      WEIGHT = "weight"
      SLANT = "slant"
      UNDERLINE = "underline"
      OVERSTRIKE = "overstrike"
  
  class Bind():
      KEY = "bind"
      LINK = "link"
      IMAGE = "image"
  
  class WTag():
      START_INDEX = "start_index"
      END_INDEX = "end_index"
  
  DEFAULT_STACK = {
      WCfg.KEY:{
          WCfg.BACKGROUND:[],
          WCfg.FOREGROUND:[("__DEFAULT__", "black")],
          WCfg.JUSTIFY:[("__DEFAULT__", 'left')],
          WCfg.TABS:[("__DEFAULT__", ())],
      },
      Fnt.KEY:{
          Fnt.FAMILY:[],
          Fnt.SIZE:[("__DEFAULT__", Defs.FONT_SIZE)],
          Fnt.WEIGHT:[("__DEFAULT__", 'normal')],
          Fnt.SLANT:[("__DEFAULT__", 'roman')],
          Fnt.UNDERLINE:[("__DEFAULT__", False)],
          Fnt.OVERSTRIKE:[("__DEFAULT__", False)],
      },
      Bind.KEY:{
          Bind.LINK:[("__DEFAULT__", None)],
      },
  }
  
  #__________________________________________________________________________________________________
  # functions
  def get_existing_font(font_families):
      #------------------------------------------------------------------------------------------
      try:
          return next(filter(lambda f: f.lower() in (f.lower() for f in font.families()), font_families))
      except:
          return "TkTextFont"
  
  
  #__________________________________________________________________________________________________
  # classes
  class HLinkSlot():
      #----------------------------------------------------------------------------------------------
  
      def __init__(self, w, tag_name, url):
          #------------------------------------------------------------------------------------------
          self._w = w
          self.tag_name = tag_name
          self.URL = url
  
      def call(self, event):
          #------------------------------------------------------------------------------------------
          webbrowser.open(self.URL)
          self._w.tag_config(self.tag_name, foreground="purple")
  
      def enter(self, event):
          #------------------------------------------------------------------------------------------
          self._w.config(cursor="hand2")
  
      def leave(self, event):
          #------------------------------------------------------------------------------------------
          self._w.config(cursor="")
  
  
  
  
  class ListTag():
      #----------------------------------------------------------------------------------------------
      def __init__(self, ordered:bool, list_type=None):
          #------------------------------------------------------------------------------------------
          self.ordered = ordered
          self.type = list_type
          self.index = 0
  
      def add(self):
          #------------------------------------------------------------------------------------------
          if self.ordered:
              self.index += 1
  
      def line_index(self):
          #------------------------------------------------------------------------------------------
          if self.ordered:
              if self.type == HTML.TypeOrderedList._1:
                  return str(self.index)
              elif self.type == HTML.TypeOrderedList.a:
                  return self._index_to_str(self.index).lower()
              elif self.type == HTML.TypeOrderedList.A:
                  return self._index_to_str(self.index).upper()
          else:
              return chr(8226)
      
      def _index_to_str(self, index):
          #------------------------------------------------------------------------------------------
          prefix = ""
          if index > 26:
              prefix = self._index_to_str(index // 26)
              index = index % 26
  
          return prefix + chr(0x60 + index)
  
  
  
  class HTMLTextParser(HTMLParser):
      #----------------------------------------------------------------------------------------------
  
      def __init__(self):
          #------------------------------------------------------------------------------------------
          super().__init__()
          # set list tabs
          self.cached_images = {}
  
          self.DEFAULT_TEXT_FONT_FAMILY = get_existing_font(Defs.DEFAULT_TEXT_FONT_FAMILY)
          self.PREFORMATTED_FONT_FAMILY = get_existing_font(Defs.PREFORMATTED_FONT_FAMILY)
  
  
      def _parse_attrs(self, attrs):
          #------------------------------------------------------------------------------------------
          attrs_dict = {
              HTML.Attrs.STYLE:{},
              HTML.Attrs.HREF:None,
              HTML.Attrs.SRC:None,
              HTML.Attrs.WIDTH:None,
              HTML.Attrs.HEIGHT:None,
              HTML.Attrs.TYPE:None,
          }
          for k, v in attrs:
              k = k.lower()
              if k == HTML.Attrs.STYLE:
                  for p in v.split(";"):
                      try:
                          p_key = p.split(":")[0].strip().lower()
                          p_value = p.split(":")[1].strip().lower()
                          attrs_dict[HTML.Attrs.STYLE][p_key] = p_value
                      except:
                          pass
              elif k in (HTML.Attrs.HREF, HTML.Attrs.SRC, HTML.Attrs.WIDTH, HTML.Attrs.HEIGHT, HTML.Attrs.TYPE):
                  attrs_dict[k] = v
          return attrs_dict
  
  
      def _w_tags_add(self):
          #------------------------------------------------------------------------------------------
          tag = {
              WCfg.KEY:{},
              Fnt.KEY:{},
              Bind.KEY:{}
          }
  
          for k1 in (WCfg.KEY, Fnt.KEY, Bind.KEY):
              for k2 in DEFAULT_STACK[k1]:
                  tag[k1][k2] = self.stack[k1][k2][-1][1]
  
          self._w_tags[self._w.index("end-1c")] = tag
  
  
      def _stack_get_main_key(self, key):
          #------------------------------------------------------------------------------------------
          if key in WCfg.__dict__.values():
              main_key = WCfg.KEY
          elif key in Fnt.__dict__.values():
              main_key = Fnt.KEY
          elif key in Bind.__dict__.values():
              main_key = Bind.KEY
          else:
              raise ValueError("key %s doesn't exists" % key)
          
          return main_key
  
  
      def _stack_add(self, tag, key, value=None):
          #------------------------------------------------------------------------------------------
          main_key = self._stack_get_main_key(key)
          
          if value is None:
              # if value is none, add the previous value
              value =  self.stack[main_key][key][-1][1]
          
          self.stack[main_key][key].append((tag, value))
  
  
      def _stack_index(self, tag, key):
          #------------------------------------------------------------------------------------------
          main_key = self._stack_get_main_key(key)
          index = None
          for i, v in enumerate(self.stack[main_key][key]):
              if v[0] == tag:
                  index = i
  
          return index
  
  
      def _stack_pop(self, tag, key):
          #------------------------------------------------------------------------------------------
          main_key = self._stack_get_main_key(key)
  
          index = None
          if len(self.stack[main_key][key]) > 1:
              index = self._stack_index(tag, key)
          
          if index is not None:
              return self.stack[main_key][key].pop(index)[1]
  
  
      def _parse_styles(self, tag, attrs):
          #------------------------------------------------------------------------------------------
          #-------------------------------------------------------------------------------- [ COLOR ]
          if HTML.Style.COLOR in attrs[HTML.Attrs.STYLE].keys():
              self._stack_add(tag, WCfg.FOREGROUND, attrs[HTML.Attrs.STYLE][HTML.Style.COLOR])
          elif tag == HTML.Tag.A and attrs[HTML.Attrs.HREF]:
              self._stack_add(tag, WCfg.FOREGROUND, "blue")
          else:
              self._stack_add(tag, WCfg.FOREGROUND)
  
          #---------------------------------------------------------------------- [ BACKGROUD_COLOR ]
          if HTML.Style.BACKGROUD_COLOR in attrs[HTML.Attrs.STYLE].keys():
              self._stack_add(tag, WCfg.BACKGROUND, attrs[HTML.Attrs.STYLE][HTML.Style.BACKGROUD_COLOR])
          elif tag == HTML.Tag.MARK:
              self._stack_add(tag, WCfg.BACKGROUND, "yellow")
          else:
              self._stack_add(tag, WCfg.BACKGROUND)
  
          #-------------------------------------------------------------------------- [ FONT_FAMILY ]
          # font family
          if HTML.Style.FONT_FAMILY in attrs[HTML.Attrs.STYLE].keys():
              font_family = Defs.DEFAULT_TEXT_FONT_FAMILY
              for f in attrs[HTML.Attrs.STYLE][HTML.Style.FONT_FAMILY].split(","):
                  f = f.strip()
                  if f in map(lambda f: f.lower(), font.families()):
                      font_family = f
                      break
              self._stack_add(tag, Fnt.FAMILY, font_family)
          elif tag in (HTML.Tag.PRE, HTML.Tag.CODE):
              self._stack_add(tag, Fnt.FAMILY, self.PREFORMATTED_FONT_FAMILY)
          else:
              self._stack_add(tag, Fnt.FAMILY)
  
          #---------------------------------------------------------------------------- [ FONT_SIZE ]
          if HTML.Style.FONT_SIZE in attrs[HTML.Attrs.STYLE].keys():
              size = Defs.FONT_SIZE
              if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE].endswith("px"):
                  if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-2].isdigit():
                      size = int(attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-2])
              elif attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE].endswith(r"%"):
                  if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-1].isdigit():
                      size = int((int(attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-1]) * Defs.FONT_SIZE)/100)
              self._stack_add(tag, Fnt.SIZE, size)
          elif tag.startswith('h') and len(tag) == 2:
              self._stack_add(tag, Fnt.SIZE, Defs.HEADINGS_FONT_SIZE[tag])
          else:
              self._stack_add(tag, Fnt.SIZE)
  
          #--------------------------------------------------------------------------- [ TEXT_ALIGN ]
          if HTML.Style.TEXT_ALIGN in attrs[HTML.Attrs.STYLE].keys() and tag in HTML.TEXT_ALIGN_TAGS:
              self._stack_add(tag, WCfg.JUSTIFY, attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_ALIGN])
          else:
              self._stack_add(tag, WCfg.JUSTIFY)
  
          #---------------------------------------------------------------------- [ TEXT_DECORATION ]
          if HTML.Style.TEXT_DECORATION in attrs[HTML.Attrs.STYLE].keys():
              if tag == HTML.Tag.STRONG:
                  self._stack_add(tag, Fnt.UNDERLINE, False)
                  self._stack_add(tag, Fnt.OVERSTRIKE, False)
              elif HTML.StyleTextDecoration.UNDERLINE in attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_DECORATION]:
                  self._stack_add(tag, Fnt.UNDERLINE, True)
                  self._stack_add(tag, Fnt.OVERSTRIKE, False)
              elif HTML.StyleTextDecoration.LINE_THROUGH in attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_DECORATION]:
                  self._stack_add(tag, Fnt.UNDERLINE, False)
                  self._stack_add(tag, Fnt.OVERSTRIKE, True)
              else:
                  self._stack_add(tag, Fnt.UNDERLINE)
                  self._stack_add(tag, Fnt.OVERSTRIKE)
          else:
              if tag == HTML.Tag.A and attrs[HTML.Attrs.HREF]:
                  self._stack_add(tag, Fnt.UNDERLINE, True)
                  self._stack_add(tag, Fnt.OVERSTRIKE, False)
              elif tag == HTML.Tag.U:
                  self._stack_add(tag, Fnt.UNDERLINE, True)
                  self._stack_add(tag, Fnt.OVERSTRIKE, False)
              else:
                  self._stack_add(tag, Fnt.UNDERLINE)
                  self._stack_add(tag, Fnt.OVERSTRIKE)
  
  
      def handle_starttag(self, tag, attrs):
          #------------------------------------------------------------------------------------------
          tag = tag.lower()
          attrs = self._parse_attrs(attrs)
  
          if tag in HTML.STYLE_TAGS:
              #---------------------------------------------------------------------- [ STYLED_TAGS ]
              self._parse_styles(tag, attrs)
  
              if tag == HTML.Tag.B or tag == HTML.Tag.STRONG or tag in HTML.HEADING_TAGS:
                  self._stack_add(tag, Fnt.WEIGHT, "bold")
  
              elif tag == HTML.Tag.I or tag == HTML.Tag.EM:
                  self._stack_add(tag, Fnt.SLANT, "italic")
  
              elif tag == HTML.Tag.A:
                  self._stack_add(tag, Bind.LINK, attrs[HTML.Attrs.HREF])
  
              elif tag == HTML.Tag.OL:
                  #---------------------------------------------------------------- [ ORDERED_LISTS ]
                  if attrs[HTML.Attrs.TYPE] and attrs[HTML.Attrs.TYPE] in HTML.TypeOrderedList.__dict__.values():
                      list_type = attrs[HTML.Attrs.TYPE]
                  else:
                      list_type = HTML.TypeOrderedList._1
                  self.list_tags.append(ListTag(ordered=True, list_type=list_type))
                  
                  tabs = []
                  for i in range(len(self.list_tags)):
                      offset = 30 * (i + 1)
                      tabs += [offset, tk.RIGHT, offset+5, tk.LEFT ]
                  self._stack_add(tag, WCfg.TABS, tabs)
  
              elif tag == HTML.Tag.UL:
                  #-------------------------------------------------------------- [ UNORDERED_LISTS ]
                  self.list_tags.append(ListTag(ordered=False))
  
                  tabs = []
                  for i in range(len(self.list_tags)):
                      offset = 30 * (i + 1)
                      tabs += [offset, tk.RIGHT, offset+5, tk.LEFT ]
                  self._stack_add(tag, WCfg.TABS, tabs)
  
              elif tag == HTML.Tag.LI:
                  #------------------------------------------------------------------ [ LISTS_LINES ]
                  level = len(self.list_tags)
                  if level:
                      self.list_tags[-1].add()
  
                      if self.strip:
                          self._insert_new_line()
  
                      line_index = self.list_tags[-1].line_index()
                      if self.list_tags[-1].ordered:
                          line_index = "\t" + "\t\t" * (level-1) + line_index + ".\t"
                      else:
                          line_index = "\t" + "\t\t" * (level-1) + line_index + "\t"
                      
                      self._stack_add(tag, Fnt.UNDERLINE, False)
                      self._stack_add(tag, Fnt.OVERSTRIKE, False)
                      self._w_tags_add()
                      self._w.insert(tk.INSERT, line_index)
                      self._stack_pop(tag, Fnt.UNDERLINE)
                      self._stack_pop(tag, Fnt.OVERSTRIKE)
  
          elif tag == HTML.Tag.IMG and attrs[HTML.Attrs.SRC]:
              #-------------------------------------------------------------------- [ UNSTYLED_TAGS ]
              image = None
              #print(attrs[HTML.Attrs.SRC] , self.cached_images)
              if attrs[HTML.Attrs.SRC].startswith(("https://" , "ftp://" , "http://")):
                  if attrs[HTML.Attrs.SRC] in self.cached_images.keys():
                      image = deepcopy(self.cached_images[attrs[HTML.Attrs.SRC]])
                  else:
                      try:
                          image = Image.open(BytesIO(requests.get(attrs[HTML.Attrs.SRC]).content))
                          self.cached_images[attrs[HTML.Attrs.SRC]] = deepcopy(image)
                      except :
                          pass
  
              if attrs[HTML.Attrs.SRC] in self.cached_images.keys():
                  image = deepcopy(self.cached_images[attrs[HTML.Attrs.SRC]])
              elif os.path.exists(attrs[HTML.Attrs.SRC]):
                  image = Image.open(attrs[HTML.Attrs.SRC])
                  self.cached_images[attrs[HTML.Attrs.SRC]] = deepcopy(image)
              if image:
                  width = image.size[0]
                  height = image.size[1]
                  resize = False
                  if str(attrs[HTML.Attrs.WIDTH]).isdigit():
                      width = int(attrs[HTML.Attrs.WIDTH])
                      resize = True
                  if str(attrs[HTML.Attrs.HEIGHT]).isdigit():
                      height = int(attrs[HTML.Attrs.HEIGHT])
                      resize = True
                  if resize:
                      image = image.resize((width, height), Image.ANTIALIAS)
                  self.images.append(ImageTk.PhotoImage(image))
                  self._w.image_create(tk.INSERT, image=self.images[-1]) 
  
          if self.strip:
              #------------------------------------------------------------------------ [ NEW_LINES ]
              if tag == HTML.Tag.BR:
                  self._insert_new_line()
              else:
                  self.html_tags.append(tag)
  
              if tag in HTML.NEW_LINE_TAGS and self.strip and self._w.index("end-1c") != "1.0":
                  if tag in (HTML.Tag.DIV,):
                      self._insert_new_line()
                  elif tag in (HTML.Tag.UL, HTML.Tag.OL):
                      if len(self.list_tags) == 1:
                          self._insert_new_line(double=True)
                      else:
                          self._insert_new_line(double=False)
                  else:       
                      self._insert_new_line(double=True)
  
          self._w_tags_add()
  
  
      def handle_charref(self, data):
          #------------------------------------------------------------------------------------------
          try:
              char = chr(int(data))
              self._w.insert(tk.INSERT, char)
          except:
              pass
  
  
      def _insert_new_line(self, double=False):
          #------------------------------------------------------------------------------------------
          self._remove_last_space()
          if self._w.get("end-3c", "end-1c") == "\n\n":
              pass
          elif self._w.get("end-2c", "end-1c") == "\n":
              if double:
                  self._w.insert(tk.INSERT, "\n")
          else:
              if double:
                  self._w.insert(tk.INSERT, "\n\n")
              else:
                  self._w.insert(tk.INSERT, "\n")
  
  
      def _text_rstrip(self):
          #------------------------------------------------------------------------------------------
          for _ in range(3):
              if self._w.get("end-2c", "end-1c") in (" ", "\n"):
                  self._w.delete("end-2c", "end-1c")
  
  
      def _remove_last_space(self):
          #------------------------------------------------------------------------------------------
          if self._w.get("end-2c", "end-1c") == " ":
              self._w.delete("end-2c", "end-1c")
  
  
      def _remove_multi_spaces(self, data):
          #------------------------------------------------------------------------------------------
          data = data.replace("  ", " ")
          if "  " in data:
              data = self._remove_multi_spaces(data)
          return data
  
  
      def handle_data(self, data):
          #------------------------------------------------------------------------------------------
          if self.strip:
              if len(self.html_tags) and self.html_tags[-1] in (HTML.Tag.PRE, HTML.Tag.CODE):
                  pass
              elif not data.strip():
                  data = ""
              else:
                  # left strip
                  if self._w.index("end-1c").endswith(".0"):
                      data = data.lstrip()
                  elif self._w.get("end-2c", "end-1c") == " ":
                      data = data.lstrip()
  
                  data = data.replace("\n", " ").replace("\t", " ")
                  data = data + " "
                  data = self._remove_multi_spaces(data)
                  if len(self.html_tags):
                      level = len(self.list_tags)
                      if self.html_tags[-1] in (HTML.Tag.UL, HTML.Tag.OL):
                          self._w.insert(tk.INSERT, "\t" * 2 * level)
  
          self._w.insert(tk.INSERT, data)
  
  
      def handle_endtag(self, tag):
          #------------------------------------------------------------------------------------------
          tag = tag.lower()
  
          try:
              index = len(self.html_tags) - self.html_tags[::-1].index(tag) - 1
              self.html_tags.pop(index)
          except:
              pass
  
          if tag in HTML.STYLE_TAGS:
  
              self._stack_pop(tag, WCfg.FOREGROUND)
              self._stack_pop(tag, WCfg.BACKGROUND)
              self._stack_pop(tag, WCfg.JUSTIFY)
              self._stack_pop(tag, Fnt.FAMILY)
              self._stack_pop(tag, Fnt.SIZE)
              self._stack_pop(tag, Fnt.UNDERLINE)
              self._stack_pop(tag, Fnt.OVERSTRIKE)
  
              if tag == HTML.Tag.B or tag == HTML.Tag.STRONG or tag in HTML.HEADING_TAGS:
                  self._stack_pop(tag, Fnt.WEIGHT)
  
              elif tag == HTML.Tag.I or tag == HTML.Tag.EM:
                  self._stack_pop(tag, Fnt.SLANT)
  
              elif tag == HTML.Tag.A:
                  self._stack_pop(tag, Bind.LINK)
  
              elif tag == HTML.Tag.OL or tag == HTML.Tag.UL:
                  if len(self.list_tags):
                      self.list_tags = self.list_tags[:-1]
  
                  self._stack_pop(tag, WCfg.TABS)
  
          if tag in HTML.NEW_LINE_TAGS and self.strip:
              self._insert_new_line()
  
          self._w_tags_add()
  
          if tag in HTML.NEW_LINE_TAGS and self.strip:
              if tag in (HTML.Tag.DIV, HTML.Tag.UL, HTML.Tag.OL):
                  if not len(self.list_tags):
                      self._insert_new_line(double=True)
              else:
                  self._insert_new_line(double=True)
  
  
      def _w_tags_apply_all(self):
          #------------------------------------------------------------------------------------------
          # update indexes
          if self.strip:
              self._text_rstrip()
          end_index = tk.END
          for key, tag in reversed(tuple(self._w_tags.items())):
              tag[WTag.START_INDEX] = key
              tag[WTag.END_INDEX] = end_index
              end_index = key
  
          # add tags
          self.hlink_slots = []
          for key, tag in self._w_tags.items():
              self._w.tag_add(key, tag[WTag.START_INDEX], tag[WTag.END_INDEX])
              self._w.tag_config(key, font=font.Font(**tag[Fnt.KEY]), **tag[WCfg.KEY])
              if tag[Bind.KEY][Bind.LINK]:
                  self.hlink_slots.append(HLinkSlot(self._w, key, tag[Bind.KEY][Bind.LINK]))
                  self._w.tag_bind(key, "<Button-1>", self.hlink_slots[-1].call)
                  self._w.tag_bind(key, "<Leave>", self.hlink_slots[-1].leave)
                  self._w.tag_bind(key, "<Enter>", self.hlink_slots[-1].enter)
          
  
      def w_set_html(self, w, html, strip):
          #------------------------------------------------------------------------------------------
          self._w = w
          self.stack = deepcopy(DEFAULT_STACK)
          self.stack[WCfg.KEY][WCfg.BACKGROUND].append(("__DEFAULT__", self._w.cget("background")))
          self.stack[Fnt.KEY][Fnt.FAMILY].append(("__DEFAULT__", self.DEFAULT_TEXT_FONT_FAMILY))
          self._w_tags = OrderedDict()
          self.html_tags = []
          self.images = []
          self.list_tags = []
          self.strip = strip
          self._w_tags_add()
          self.feed(html)
          self._w_tags_apply_all()
          del self._w
  