nodes: 0, module; 1, function_definition; 2, function_name:_GetEventIdentifiers; 3, parameters; 4, block; 5, identifier:self; 6, identifier:event; 7, expression_statement; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, for_statement; 12, comment:# The 'atime', 'ctime', 'crtime', 'mtime' are included for backwards; 13, comment:# compatibility with the filestat parser.; 14, if_statement; 15, expression_statement; 16, expression_statement; 17, return_statement; 18, comment:"""Retrieves different identifiers of the event.
  
      Every event contains event data, which consists of attributes and values.
      These attributes and values can be represented as a string and used for
      sorting and uniquely identifying events. This function determines multiple
      identifiers:
      * an identifier of the attributes and values without the timestamp
        description (or usage). This is referred to as the MACB group
        identifier.
      * an identifier of the attributes and values including the timestamp
        description (or usage). This is referred to as the event content
        identifier.
  
      The identifier without the timestamp description can be used to group
      events that have the same MACB (modification, access, change, birth)
      timestamps. The PsortEventHeap will store these events individually and
      relies on PsortMultiProcessEngine to do the actual grouping of events.
  
      Args:
        event (EventObject): event.
  
      Returns:
        tuple: containing:
  
          str: identifier of the event MACB group or None if the event cannot
              be grouped.
          str: identifier of the event content.
      """; 19, assignment; 20, assignment; 21, call; 22, pattern_list; 23, call; 24, block; 25, comparison_operator:event.timestamp_desc in (
          'atime', 'ctime', 'crtime', 'mtime',
          definitions.TIME_DESCRIPTION_LAST_ACCESS,
          definitions.TIME_DESCRIPTION_CHANGE,
          definitions.TIME_DESCRIPTION_CREATION,
          definitions.TIME_DESCRIPTION_MODIFICATION); 26, block; 27, else_clause; 28, call; 29, assignment; 30, expression_list; 31, identifier:attributes; 32, list; 33, identifier:attribute_string; 34, call; 35, attribute; 36, argument_list; 37, identifier:attribute_name; 38, identifier:attribute_value; 39, identifier:sorted; 40, argument_list; 41, if_statement; 42, if_statement; 43, if_statement; 44, try_statement; 45, expression_statement; 46, attribute; 47, tuple; 48, expression_statement; 49, block; 50, attribute; 51, argument_list; 52, identifier:content_identifier; 53, call; 54, identifier:macb_group_identifier; 55, identifier:content_identifier; 56, attribute; 57, argument_list; 58, identifier:attributes; 59, identifier:append; 60, identifier:attribute_string; 61, call; 62, comparison_operator:attribute_name in self._IDENTIFIER_EXCLUDED_ATTRIBUTES; 63, block; 64, not_operator; 65, block; 66, comparison_operator:attribute_name == 'pathspec'; 67, block; 68, elif_clause; 69, elif_clause; 70, elif_clause; 71, block; 72, except_clause; 73, call; 74, identifier:event; 75, identifier:timestamp_desc; 76, string; 77, string; 78, string; 79, string; 80, attribute; 81, attribute; 82, attribute; 83, attribute; 84, assignment; 85, expression_statement; 86, identifier:attributes; 87, identifier:insert; 88, integer:0; 89, attribute; 90, attribute; 91, argument_list; 92, string; 93, identifier:format; 94, attribute; 95, attribute; 96, argument_list; 97, identifier:attribute_name; 98, attribute; 99, continue_statement; 100, identifier:attribute_value; 101, continue_statement; 102, identifier:attribute_name; 103, string; 104, expression_statement; 105, call; 106, block; 107, call; 108, block; 109, call; 110, block; 111, expression_statement; 112, identifier:UnicodeDecodeError; 113, block; 114, attribute; 115, argument_list; 116, string_content:atime; 117, string_content:ctime; 118, string_content:crtime; 119, string_content:mtime; 120, identifier:definitions; 121, identifier:TIME_DESCRIPTION_LAST_ACCESS; 122, identifier:definitions; 123, identifier:TIME_DESCRIPTION_CHANGE; 124, identifier:definitions; 125, identifier:TIME_DESCRIPTION_CREATION; 126, identifier:definitions; 127, identifier:TIME_DESCRIPTION_MODIFICATION; 128, identifier:macb_group_identifier; 129, call; 130, assignment; 131, identifier:event; 132, identifier:timestamp_desc; 133, string; 134, identifier:join; 135, identifier:attributes; 136, string_content:data_type: {0:s}; 137, identifier:event; 138, identifier:data_type; 139, identifier:event; 140, identifier:GetAttributes; 141, identifier:self; 142, identifier:_IDENTIFIER_EXCLUDED_ATTRIBUTES; 143, string_content:pathspec; 144, assignment; 145, identifier:isinstance; 146, argument_list; 147, expression_statement; 148, identifier:isinstance; 149, argument_list; 150, expression_statement; 151, identifier:isinstance; 152, argument_list; 153, expression_statement; 154, assignment; 155, expression_statement; 156, identifier:attributes; 157, identifier:append; 158, identifier:attribute_string; 159, attribute; 160, argument_list; 161, identifier:macb_group_identifier; 162, None; 163, string_content:,; 164, identifier:attribute_value; 165, attribute; 166, identifier:attribute_value; 167, identifier:dict; 168, assignment; 169, identifier:attribute_value; 170, identifier:set; 171, assignment; 172, identifier:attribute_value; 173, attribute; 174, assignment; 175, identifier:attribute_string; 176, call; 177, call; 178, string; 179, identifier:join; 180, identifier:attributes; 181, identifier:attribute_value; 182, identifier:comparable; 183, identifier:attribute_value; 184, call; 185, identifier:attribute_value; 186, call; 187, identifier:py2to3; 188, identifier:BYTES_TYPE; 189, identifier:attribute_value; 190, call; 191, attribute; 192, argument_list; 193, attribute; 194, argument_list; 195, string_content:,; 196, identifier:sorted; 197, argument_list; 198, identifier:sorted; 199, argument_list; 200, identifier:repr; 201, argument_list; 202, string; 203, identifier:format; 204, identifier:attribute_name; 205, identifier:attribute_value; 206, identifier:logger; 207, identifier:error; 208, call; 209, call; 210, call; 211, identifier:attribute_value; 212, string_content:{0:s}: {1!s}; 213, attribute; 214, argument_list; 215, attribute; 216, argument_list; 217, identifier:list; 218, argument_list; 219, string; 220, identifier:format; 221, identifier:attribute_name; 222, identifier:attribute_value; 223, identifier:items; 224, identifier:attribute_value; 225, string_content:Failed to decode attribute {0:s}
code: def _GetEventIdentifiers(self, event):
      """Retrieves different identifiers of the event.
  
      Every event contains event data, which consists of attributes and values.
      These attributes and values can be represented as a string and used for
      sorting and uniquely identifying events. This function determines multiple
      identifiers:
      * an identifier of the attributes and values without the timestamp
        description (or usage). This is referred to as the MACB group
        identifier.
      * an identifier of the attributes and values including the timestamp
        description (or usage). This is referred to as the event content
        identifier.
  
      The identifier without the timestamp description can be used to group
      events that have the same MACB (modification, access, change, birth)
      timestamps. The PsortEventHeap will store these events individually and
      relies on PsortMultiProcessEngine to do the actual grouping of events.
  
      Args:
        event (EventObject): event.
  
      Returns:
        tuple: containing:
  
          str: identifier of the event MACB group or None if the event cannot
              be grouped.
          str: identifier of the event content.
      """
      attributes = []
  
      attribute_string = 'data_type: {0:s}'.format(event.data_type)
      attributes.append(attribute_string)
  
      for attribute_name, attribute_value in sorted(event.GetAttributes()):
        if attribute_name in self._IDENTIFIER_EXCLUDED_ATTRIBUTES:
          continue
  
        if not attribute_value:
          continue
  
        if attribute_name == 'pathspec':
          attribute_value = attribute_value.comparable
  
        elif isinstance(attribute_value, dict):
          attribute_value = sorted(attribute_value.items())
  
        elif isinstance(attribute_value, set):
          attribute_value = sorted(list(attribute_value))
  
        elif isinstance(attribute_value, py2to3.BYTES_TYPE):
          attribute_value = repr(attribute_value)
  
        try:
          attribute_string = '{0:s}: {1!s}'.format(
              attribute_name, attribute_value)
        except UnicodeDecodeError:
          logger.error('Failed to decode attribute {0:s}'.format(
              attribute_name))
        attributes.append(attribute_string)
  
      # The 'atime', 'ctime', 'crtime', 'mtime' are included for backwards
      # compatibility with the filestat parser.
      if event.timestamp_desc in (
          'atime', 'ctime', 'crtime', 'mtime',
          definitions.TIME_DESCRIPTION_LAST_ACCESS,
          definitions.TIME_DESCRIPTION_CHANGE,
          definitions.TIME_DESCRIPTION_CREATION,
          definitions.TIME_DESCRIPTION_MODIFICATION):
        macb_group_identifier = ', '.join(attributes)
      else:
        macb_group_identifier = None
  
      attributes.insert(0, event.timestamp_desc)
      content_identifier = ', '.join(attributes)
  
      return macb_group_identifier, content_identifier