docs: def explore(layer=None):
      """Function used to discover the Scapy layers and protocols.
      It helps to see which packets exists in contrib or layer files.
  
      params:
       - layer: If specified, the function will explore the layer. If not,
                the GUI mode will be activated, to browse the available layers
  
      examples:
        >>> explore()  # Launches the GUI
        >>> explore("dns")  # Explore scapy.layers.dns
        >>> explore("http2")  # Explore scapy.contrib.http2
        >>> explore(scapy.layers.bluetooth4LE)
  
      Note: to search a packet by name, use ls("name") rather than explore.
      """
      if layer is None:  # GUI MODE
          if not conf.interactive:
              raise Scapy_Exception("explore() GUI-mode cannot be run in "
                                    "interactive mode. Please provide a "
                                    "'layer' parameter !")
          # 0 - Imports
          try:
              import prompt_toolkit
          except ImportError:
              raise ImportError("prompt_toolkit is not installed ! "
                                "You may install IPython, which contains it, via"
                                " `pip install ipython`")
          if not _version_checker(prompt_toolkit, (2, 0)):
              raise ImportError("prompt_toolkit >= 2.0.0 is required !")
          # Only available with prompt_toolkit > 2.0, not released on PyPi yet
          from prompt_toolkit.shortcuts.dialogs import radiolist_dialog, \
              button_dialog
          from prompt_toolkit.formatted_text import HTML
          # 1 - Ask for layer or contrib
          action = button_dialog(
              title="Scapy v%s" % conf.version,
              text=HTML(
                  six.text_type(
                      '<style bg="white" fg="red">Chose the type of packets'
                      ' you want to explore:</style>'
                  )
              ),
              buttons=[
                  (six.text_type("Layers"), "layers"),
                  (six.text_type("Contribs"), "contribs"),
                  (six.text_type("Cancel"), "cancel")
              ])
          # 2 - Retrieve list of Packets
          if action == "layers":
              # Get all loaded layers
              _radio_values = conf.layers.layers()
              # Restrict to layers-only (not contribs) + packet.py and asn1*.py
              _radio_values = [x for x in _radio_values if ("layers" in x[0] or
                                                            "packet" in x[0] or
                                                            "asn1" in x[0])]
          elif action == "contribs":
              # Get all existing contribs
              from scapy.main import list_contrib
              _radio_values = list_contrib(ret=True)
              _radio_values = [(x['name'], x['description'])
                               for x in _radio_values]
              # Remove very specific modules
              _radio_values = [x for x in _radio_values if not ("can" in x[0])]
          else:
              # Escape/Cancel was pressed
              return
          # Python 2 compat
          if six.PY2:
              _radio_values = [(six.text_type(x), six.text_type(y))
                               for x, y in _radio_values]
          # 3 - Ask for the layer/contrib module to explore
          result = radiolist_dialog(
              values=_radio_values,
              title="Scapy v%s" % conf.version,
              text=HTML(
                  six.text_type(
                      '<style bg="white" fg="red">Please select a layer among'
                      ' the following, to see all packets contained in'
                      ' it:</style>'
                  )
              ))
          if result is None:
              return  # User pressed "Cancel"
          # 4 - (Contrib only): load contrib
          if action == "contribs":
              from scapy.main import load_contrib
              load_contrib(result)
              result = "scapy.contrib." + result
      else:  # NON-GUI MODE
          # We handle layer as a short layer name, full layer name
          # or the module itself
          if isinstance(layer, types.ModuleType):
              layer = layer.__name__
          if isinstance(layer, str):
              if layer.startswith("scapy.layers."):
                  result = layer
              else:
                  if layer.startswith("scapy.contrib."):
                      layer = layer.replace("scapy.contrib.", "")
                  from scapy.main import load_contrib
                  load_contrib(layer)
                  result_layer, result_contrib = (("scapy.layers.%s" % layer),
                                                  ("scapy.contrib.%s" % layer))
                  if result_layer in conf.layers.ldict:
                      result = result_layer
                  elif result_contrib in conf.layers.ldict:
                      result = result_contrib
                  else:
                      raise Scapy_Exception("Unknown scapy module '%s'" % layer)
          else:
              warning("Wrong usage ! Check out help(explore)")
              return
  
      # COMMON PART
      # Get the list of all Packets contained in that module
      try:
          all_layers = conf.layers.ldict[result]
      except KeyError:
          raise Scapy_Exception("Unknown scapy module '%s'" % layer)
      # Print
      print(conf.color_theme.layer_name("Packets contained in %s:" % result))
      rtlst = [(lay.__name__ or "", lay._name or "") for lay in all_layers]
      print(pretty_list(rtlst, [("Class", "Name")], borders=True))