You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: filter.go
    path of file: ./repos/tracee/pkg/cmd/flags
    
    the code of the file until where you have to start completion: package flags

import (
	"strings"

	"github.com/aquasecurity/tracee/pkg/events"
)

func filterHelp() string {
	return `Select which events to trace by defining filter expressions that operate on some scope (workload), events or process metadata.
Only events that match all filter expressions will be traced (flags are ANDed).
The following types of expressions are supported:

Numerical expressions which compare numbers and allow the following operators: '=', '!=', '<', '>'.
Available numerical expressions: uid, pid, mntns, pidns.
NOTE: Expressions containing '<' or '>' token must be escaped! This is also shown in the examples below.

String expressions which compares text and allow the following operators: '=', '!='.
Available string expressions: uts, comm, container, executable.

Boolean expressions that check if a boolean is true and allow the following operator: '!'.
Available boolean expressions: container.

Event flag selects events or sets of events to trace according to predefined sets, which can be listed by using the 'list' flag.
Event flag uses a dash prefix to filter out events: '-'.

Event arguments can be accessed using 'event_name.args.event_arg' and provide a way to filter an event by its arguments.
Event arguments allow the following operators: '=', '!='.
Strings can be compared as a prefix if ending with '*' or as suffix if starting with '*'.

Event return value can be accessed using 'event_name.retval' and provide a way to filter an event by its return value.
Event return value expression has the same syntax as a numerical expression.

Event context fields can be accessed using 'event_name.context.field', this can be used to filter an event by the non arguments
fields defined in the trace.Event struct.
Refer to the json tags in the trace.Event struct located in the types/trace package for the correct field names, and the event filtering
section in the documentation for a full list.

Non-boolean expressions can compare a field to multiple values separated by ','.
Multiple values are ORed if used with equals operator '=', but are ANDed if used with any other operator.

The field 'container' and 'pid' also support the special value 'new' which selects new containers or
    
func prepareEventsToTrace(eventFilter eventFilter, eventsNameToID map[string]events.ID) (map[events.ID]string, error) {
	eventsToTrace := eventFilter.Equal
	excludeEvents := eventFilter.NotEqual
	var setsToTrace []string

	var idToName map[events.ID]string
	setsToEvents := make(map[string][]events.ID)
	isExcluded := make(map[events.ID]bool)

	// build a map: k:set, v:eventID
	for _, eventDefinition := range events.Core.GetDefinitions() {
		for _, set := range eventDefinition.GetSets() {
			setsToEvents[set] = append(setsToEvents[set], eventDefinition.GetID())
		}
	}

	// mark excluded events (isExcluded) by their id
	for _, name := range excludeEvents {
		if strings.HasSuffix(name, "*") { // handle event prefixes with wildcards
			found := false
			prefix := name[:len(name)-1]
			for event, id := range eventsNameToID {
				if strings.HasPrefix(event, prefix) {
					isExcluded[id] = true
					found = true
				}
			}
			if !found {
				return nil, InvalidEventExcludeError(name)
			}
		} else {
			id, ok := eventsNameToID[name]
			if !ok {
				return nil, InvalidEventExcludeError(name)
			}
			isExcluded[id] = true
		}
	}

	// if no events were specified, add all events from the default set
	if len(eventsToTrace) == 0 {
		setsToTrace = append(setsToTrace, "default")
	}

	// build a map: k:eventID, v:eventName with all events to trace
	idToName = make(map[events.ID]string, events.Core.Length())
	for _, name := range eventsToTrace {
		if strings.HasSuffix(name, "*") { // handle event prefixes with wildcards
			found := false
			prefix := name[:len(name)-1]
			for event, id := range eventsNameToID {
				if strings.HasPrefix(event, prefix) && !isExcluded[id] {
					idToName[id] = event
					found = true
				}
			}
			if !found {
				return nil, InvalidEventError(name)
			}
		} else {
			id, ok := eventsNameToID[name]
			if !ok {
				// no matching event - maybe it is actually a set?
				if _, ok = setsToEvents[name]; ok {
					setsToTrace = append(setsToTrace, name)
					continue
				}
				return nil, InvalidEventError(name)
			}
			idToName[id] = name
		}
	}

	// add events from sets to the map containing events to trace
	for _, set := range setsToTrace {
		setEvents := setsToEvents[set]
		for _, id := range setEvents {
			if !isExcluded[id] {
				idToName[id] = events.Core.GetDefinitionByID(id).GetName()
			}
		}
	}

	return idToName, nil
}