code: func (h *Handler) GetPermanodesWithAttr(req *WithAttrRequest) (*WithAttrResponse, error) {
  	ctx := context.TODO()
  
  	h.index.RLock()
  	defer h.index.RUnlock()
  
  	ch := make(chan blob.Ref, buffered)
  	errch := make(chan error, 1)
  	go func() {
  		signer := req.Signer
  		if !signer.Valid() {
  			signer = h.owner.BlobRef()
  		}
  		errch <- h.index.SearchPermanodesWithAttr(ctx, ch,
  			&camtypes.PermanodeByAttrRequest{
  				Attribute:  req.Attr,
  				Query:      req.Value,
  				Signer:     signer,
  				FuzzyMatch: req.Fuzzy,
  				MaxResults: req.N,
  				At:         req.At,
  			})
  	}()
  
  	dr := h.NewDescribeRequest()
  
  	var withAttr []*WithAttrItem
  	for res := range ch {
  		dr.StartDescribe(ctx, res, 2)
  		withAttr = append(withAttr, &WithAttrItem{
  			Permanode: res,
  		})
  	}
  
  	metaMap, err := dr.metaMap()
  	if err != nil {
  		return nil, err
  	}
  
  	if err := <-errch; err != nil {
  		return nil, err
  	}
  
  	res := &WithAttrResponse{
  		WithAttr: withAttr,
  		Meta:     metaMap,
  	}
  	return res, nil
  }
docs: // GetPermanodesWithAttr returns permanodes with attribute req.Attr
  // having the req.Value as a value.
  // See WithAttrRequest for more details about the query.