code: def LookupClients(self, keywords):
      
      if isinstance(keywords, string_types):
        raise ValueError(
            "Keywords should be an iterable, not a string (got %s)." % keywords)
  
      start_time, end_time, filtered_keywords, unversioned_keywords = (
          self._AnalyzeKeywords(keywords))
  
      last_seen_map = None
      if unversioned_keywords:
        last_seen_map = {}
  
      # TODO(user): Make keyword index datetime aware so that
      # AsMicrosecondsSinceEpoch is unnecessary.
  
      raw_results = self.Lookup(
          list(map(self._NormalizeKeyword, filtered_keywords)),
          start_time=start_time.AsMicrosecondsSinceEpoch(),
          end_time=end_time.AsMicrosecondsSinceEpoch(),
          last_seen_map=last_seen_map)
      if not raw_results:
        return []
  
      if unversioned_keywords:
        universal_last_seen_raw = {}
        self.ReadPostingLists(
            list(map(self._NormalizeKeyword, raw_results)),
            start_time=start_time.AsMicrosecondsSinceEpoch(),
            end_time=end_time.AsMicrosecondsSinceEpoch(),
            last_seen_map=universal_last_seen_raw)
  
        universal_last_seen = {}
        for (_, client_id), ts in iteritems(universal_last_seen_raw):
          universal_last_seen[client_id] = ts
  
        old_results = set()
        for keyword in unversioned_keywords:
          for result in raw_results:
            if last_seen_map[(keyword, result)] < universal_last_seen[result]:
              old_results.add(result)
        raw_results -= old_results
  
      return [rdf_client.ClientURN(result) for result in raw_results]
docs: Returns a list of client URNs associated with keywords.
  
      Args:
        keywords: The list of keywords to search by.
  
      Returns:
        A list of client URNs.
  
      Raises:
        ValueError: A string (single keyword) was passed instead of an iterable.