code: def find_loaders(scheme, protocols=None):
      
      # build a list of all required entry points
      matching_groups = ['plaster.loader_factory']
      if protocols:
          matching_groups += [
              'plaster.{0}_loader_factory'.format(proto)
              for proto in protocols
          ]
      scheme = scheme.lower()
  
      # if a distribution is specified then it overrides the default search
      parts = scheme.split('+', 1)
      if len(parts) == 2:
          try:
              distro = pkg_resources.get_distribution(parts[0])
          except pkg_resources.DistributionNotFound:
              pass
          else:
              ep = _find_ep_in_dist(distro, parts[1], matching_groups)
  
              # if we got one or more loaders from a specific distribution
              # then they override everything else so we'll just return them
              if ep:
                  return [EntryPointLoaderInfo(ep, protocols)]
  
      # find any distributions supporting the default loader protocol
      possible_entry_points = [
          ep
          for ep in pkg_resources.iter_entry_points('plaster.loader_factory')
          if scheme is None or scheme == ep.name.lower()
      ]
      distros = {ep.dist for ep in possible_entry_points}
      matched_entry_points = list(filter(None, [
          _find_ep_in_dist(distro, scheme, matching_groups)
          for distro in distros
      ]))
      return [
          EntryPointLoaderInfo(ep, protocols=protocols)
          for ep in matched_entry_points
      ]
docs: Find all loaders that match the requested scheme and protocols.
  
      :param scheme: Any valid scheme. Examples would be something like ``ini``
          or ``ini+pastedeploy``.
  
      :param protocols: Zero or more :term:`loader protocol` identifiers that
          the loader must implement. If ``None`` then only generic loaders will
          be returned.
  
      :returns: A list containing zero or more :class:`plaster.ILoaderInfo`
          objects.