'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.'

def LookupClients(self, keywords):

    if isinstance(keywords, basestring):
        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 = {}
    raw_results = self.Lookup(map(self._NormalizeKeyword, filtered_keywords), start_time=start_time.AsMicroSecondsFromEpoch(), end_time=end_time.AsMicroSecondsFromEpoch(), last_seen_map=last_seen_map)
    if (not raw_results):
        return []
    if unversioned_keywords:
        universal_last_seen_raw = {}
        self.ReadPostingLists(map(self._NormalizeKeyword, raw_results), start_time=start_time.AsMicroSecondsFromEpoch(), end_time=end_time.AsMicroSecondsFromEpoch(), last_seen_map=universal_last_seen_raw)
        universal_last_seen = {}
        for ((_, client_id), ts) in universal_last_seen_raw.iteritems():
            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]
