code: func Find(ctx context.Context, ir io.Reader, hashesToFind []uint32, size int) (map[uint32][]int64, error) {
  	if ir == nil || len(hashesToFind) == 0 {
  		return nil, nil
  	}
  
  	r := bufio.NewReader(ir)
  	hf := adler32.New()
  
  	n, err := io.CopyN(hf, r, int64(size))
  	if err == io.EOF {
  		return nil, nil
  	}
  	if err != nil {
  		return nil, err
  	}
  	if n != int64(size) {
  		return nil, io.ErrShortBuffer
  	}
  
  	offsets := make(map[uint32][]int64)
  	for _, hashToFind := range hashesToFind {
  		offsets[hashToFind] = make([]int64, 0, maxWeakhashFinderHits)
  	}
  
  	var i int64
  	var hash uint32
  	for {
  		select {
  		case <-ctx.Done():
  			return nil, ctx.Err()
  		default:
  		}
  
  		hash = hf.Sum32()
  		if existing, ok := offsets[hash]; ok && len(existing) < maxWeakhashFinderHits {
  			offsets[hash] = append(existing, i)
  		}
  		i++
  
  		bt, err := r.ReadByte()
  		if err == io.EOF {
  			break
  		} else if err != nil {
  			return offsets, err
  		}
  		hf.Roll(bt)
  	}
  	return offsets, nil
  }
docs: // Find finds all the blocks of the given size within io.Reader that matches
  // the hashes provided, and returns a hash -> slice of offsets within reader
  // map, that produces the same weak hash.