'Publish the message into all listeners of the event.
If event_name is a string, we send the message to all event handlers which
contain this string in their EVENT static member. This allows the event to
be sent to multiple interested listeners. Alternatively, the event_name can
specify a single URN of an event listener to receive the message.
Args:
events: A dict with keys being event names and values being lists of
messages.
delay: An rdfvalue.Duration object. If given, the event will be published
after the indicated time.
token: ACL token.
Raises:
ValueError: If the message is invalid. The message must be a Semantic
Value (instance of RDFValue) or a full GrrMessage.'

@classmethod
def PublishMultipleEvents(cls, events, delay=None, token=None):

    with queue_manager.WellKnownQueueManager(token=token) as manager:
        event_name_map = registry.EventRegistry.EVENT_NAME_MAP
        for (event_name, messages) in events.iteritems():
            handler_urns = []
            if isinstance(event_name, basestring):
                for event_cls in event_name_map.get(event_name, []):
                    if (event_cls.well_known_session_id is None):
                        logging.error('Well    known    flow    %s    has    no    session_id.', event_cls.__name__)
                    else:
                        handler_urns.append(event_cls.well_known_session_id)
            else:
                handler_urns.append(event_name)
            for msg in messages:
                if (not isinstance(msg, rdfvalue.RDFValue)):
                    raise ValueError('Can    only    publish    RDFValue    instances.')
                if (not isinstance(msg, rdf_flows.GrrMessage)):
                    msg = rdf_flows.GrrMessage(payload=msg)
                msg.response_id = msg.task_id = msg.GenerateTaskID()
                msg.request_id = 0
                timestamp = None
                if delay:
                    timestamp = (rdfvalue.RDFDatetime.Now() + delay).AsMicroSecondsFromEpoch()
                for event_urn in handler_urns:
                    tmp_msg = msg.Copy()
                    tmp_msg.session_id = event_urn
                    manager.QueueResponse(tmp_msg)
                    manager.QueueNotification(rdf_flows.GrrNotification(session_id=event_urn, priority=msg.priority, timestamp=timestamp))
