code: func NewMatcher(sectionSize uint64, filters [][][]byte) *Matcher {
  	// Create the matcher instance
  	m := &Matcher{
  		sectionSize: sectionSize,
  		schedulers:  make(map[uint]*scheduler),
  		retrievers:  make(chan chan uint),
  		counters:    make(chan chan uint),
  		retrievals:  make(chan chan *Retrieval),
  		deliveries:  make(chan *Retrieval),
  	}
  	// Calculate the bloom bit indexes for the groups we're interested in
  	m.filters = nil
  
  	for _, filter := range filters {
  		// Gather the bit indexes of the filter rule, special casing the nil filter
  		if len(filter) == 0 {
  			continue
  		}
  		bloomBits := make([]bloomIndexes, len(filter))
  		for i, clause := range filter {
  			if clause == nil {
  				bloomBits = nil
  				break
  			}
  			bloomBits[i] = calcBloomIndexes(clause)
  		}
  		// Accumulate the filter rules if no nil rule was within
  		if bloomBits != nil {
  			m.filters = append(m.filters, bloomBits)
  		}
  	}
  	// For every bit, create a scheduler to load/download the bit vectors
  	for _, bloomIndexLists := range m.filters {
  		for _, bloomIndexList := range bloomIndexLists {
  			for _, bloomIndex := range bloomIndexList {
  				m.addScheduler(bloomIndex)
  			}
  		}
  	}
  	return m
  }
docs: // NewMatcher creates a new pipeline for retrieving bloom bit streams and doing
  // address and topic filtering on them. Setting a filter component to `nil` is
  // allowed and will result in that filter rule being skipped (OR 0x11...1).