'Opens hunts results metadata in bulk and groups the by verifier type.
We\'ve traded simplicity for performance here. Initial implementations of
VerifyHuntOutputPluginsCronFlow checked the hunts one-by-one, but that
turned out to be too slow and inefficient when many hunts had to be
checked. To make the checks more effective, MultiVerifyHuntOutput()
method was introduced in the verifiers API.
It\'s this cron flow\'s responsibility to group the plugin objects by
verifier type, so that we can feed them to MultiVerifyHuntOutput.
Args:
hunts: A list of GRRHunt objects.
Returns:
A dictionary where keys are verifier classes and values are lists of
tuples (plugin id, plugin descriptor, plugin object, hunt object).
Special constant NON_VERIFIABLE is used as a key for plugins that
have no corresponding verifier.'

def _GroupHuntsAndPluginsByVerifiers(self, hunts):

    hunts_by_urns = {}
    for hunt in hunts:
        hunts_by_urns[hunt.urn] = hunt
    results_metadata_urns = [hunt.results_metadata_urn for hunt in hunts]
    results_metadata_objects = aff4.FACTORY.MultiOpen(results_metadata_urns, aff4_type=implementation.HuntResultsMetadata, token=self.token)
    results = {}
    for mdata in results_metadata_objects:
        hunt_urn = rdfvalue.RDFURN(mdata.urn.Dirname())
        hunt = hunts_by_urns[hunt_urn]
        for (plugin_id, (plugin_descriptor, plugin_state)) in mdata.Get(mdata.Schema.OUTPUT_PLUGINS, {}).items():
            plugin_obj = plugin_descriptor.GetPluginForState(plugin_state)
            plugin_verifiers_classes = plugin_descriptor.GetPluginVerifiersClasses()
            if (not plugin_verifiers_classes):
                results.setdefault(self.NON_VERIFIABLE, []).append((plugin_id, plugin_descriptor, plugin_obj, hunt))
            else:
                for cls in plugin_verifiers_classes:
                    results.setdefault(cls, []).append((plugin_id, plugin_descriptor, plugin_obj, hunt))
    return results
