code: func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) {
  	apiResolveCount.Inc(1)
  	log.Trace("resolving", "uri", uri.Addr)
  
  	var sp opentracing.Span
  	ctx, sp = spancontext.StartSpan(
  		ctx,
  		"api.resolve")
  	defer sp.Finish()
  
  	// if the URI is immutable, check if the address looks like a hash
  	if uri.Immutable() {
  		key := uri.Address()
  		if key == nil {
  			return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr)
  		}
  		return key, nil
  	}
  
  	addr, err := a.Resolve(ctx, uri.Addr)
  	if err != nil {
  		return nil, err
  	}
  
  	if uri.Path == "" {
  		return addr, nil
  	}
  	walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil)
  	if err != nil {
  		return nil, err
  	}
  	var entry *ManifestEntry
  	walker.Walk(func(e *ManifestEntry) error {
  		// if the entry matches the path, set entry and stop
  		// the walk
  		if e.Path == uri.Path {
  			entry = e
  			// return an error to cancel the walk
  			return errors.New("found")
  		}
  		// ignore non-manifest files
  		if e.ContentType != ManifestType {
  			return nil
  		}
  		// if the manifest's path is a prefix of the
  		// requested path, recurse into it by returning
  		// nil and continuing the walk
  		if strings.HasPrefix(uri.Path, e.Path) {
  			return nil
  		}
  		return ErrSkipManifest
  	})
  	if entry == nil {
  		return nil, errors.New("not found")
  	}
  	addr = storage.Address(common.Hex2Bytes(entry.Hash))
  	return addr, nil
  }
docs: // Resolve resolves a URI to an Address using the MultiResolver.