func (n *ProtoNode) ResolveLink(path []string) (*format.Link, []string, error) {
	if len(path) == 0 {
		return nil, nil, fmt.Errorf("end of path, no more links to resolve")
	}
	lnk, err := n.GetNodeLink(path[0])
	if err != nil {
		return nil, nil, err
	}
	return lnk, path[1:], nil
}
ResolveLink consumes the first element of the path and obtains the link
corresponding to it from the node. It returns the link
and the path without the consumed element.
package merkledag
import (
	"context"
	"encoding/json"
	"fmt"
	blocks "github.com/ipfs/go-block-format"
	cid "github.com/ipfs/go-cid"
	format "github.com/ipfs/go-ipld-format"
	legacy "github.com/ipfs/go-ipld-legacy"
	dagpb "github.com/ipld/go-codec-dagpb"
	ipld "github.com/ipld/go-ipld-prime"
	mh "github.com/multiformats/go-multihash"
)
var (
	ErrNotProtobuf  = fmt.Errorf("expected protobuf dag node")
	ErrNotRawNode   = fmt.Errorf("expected raw bytes node")
	ErrLinkNotFound = fmt.Errorf("no link by that name")
)
type immutableProtoNode struct {
	encoded []byte
	dagpb.PBNode
}
type ProtoNode struct {
	links []*format.Link
	data  []byte
	encoded *immutableProtoNode
	cached  cid.Cid
	builder cid.Builder
}
var v0CidPrefix = cid.Prefix{
	Codec:    cid.DagProtobuf,
	MhLength: -1,
	MhType:   mh.SHA2_256,
	Version:  0,
}
var v1CidPrefix = cid.Prefix{
	Codec:    cid.DagProtobuf,
	MhLength: -1,
	MhType:   mh.SHA2_256,
	Version:  1,
}
func V0CidPrefix() cid.Prefix { return v0CidPrefix }
func V1CidPrefix() cid.Prefix { return v1CidPrefix }
func PrefixForCidVersion(version int) (cid.Prefix, error) {
	switch version {
	case 0:
		return v0CidPrefix, nil
	case 1:
		return v1CidPrefix, nil
	default:
		return cid.Prefix{}, fmt.Errorf("unknown CID version: %d", version)
	}
}
func (n *ProtoNode) CidBuilder() cid.Builder {
	if n.builder == nil {
		n.builder = v0CidPrefix
	}
	return n.builder
}
func (n *ProtoNode) SetCidBuilder(builder cid.Builder) {
	if builder == nil {
		n.builder = v0CidPrefix
	} else {
		n.builder = builder.WithCodec(cid.DagProtobuf)
		n.cached = cid.Undef
	}
}
type LinkSlice []*format.Link
func (ls LinkSlice) Len() int           { return len(ls) }
func (ls LinkSlice) Swap(a, b int)      { ls[a], ls[b] = ls[b], ls[a] }
func (ls LinkSlice) Less(a, b int) bool { return ls[a].Name < ls[b].Name }
func NodeWithData(d []byte) *ProtoNode {
	return &ProtoNode{data: d}
}
func (n *ProtoNode) AddNodeLink(name string, that format.Node) error {
	lnk, err := format.MakeLink(that)
	if err != nil {
		return err
	}
	lnk.Name = name
	n.AddRawLink(name, lnk)
	return nil
}
func (n *ProtoNode) AddRawLink(name string, l *format.Link) error {
	n.encoded = nil
	n.links = append(n.links, &format.Link{
		Name: name,
		Size: l.Size,
		Cid:  l.Cid,
	})
	return nil
}
func (n *ProtoNode) RemoveNodeLink(name string) error {
	n.encoded = nil
	ref := n.links[:0]
	found := false
	for _, v := range n.links {
		if v.Name != name {
			ref = append(ref, v)
		} else {
			found = true
		}
	}
	if !found {
		return ErrLinkNotFound
	}
	n.links = ref
	return nil
}
func (n *ProtoNode) GetNodeLink(name string) (*format.Link, error) {
	for _, l := range n.links {
		if l.Name == name {
			return &format.Link{
				Name: l.Name,
				Size: l.Size,
				Cid:  l.Cid,
			}, nil
		}
	}
	return nil, ErrLinkNotFound
}
func (n *ProtoNode) GetLinkedProtoNode(ctx context.Context, ds format.DAGService, name string) (*ProtoNode, error) {
	nd, err := n.GetLinkedNode(ctx, ds, name)
	if err != nil {
		return nil, err
	}
	pbnd, ok := nd.(*ProtoNode)
	if !ok {
		return nil, ErrNotProtobuf
	}
	return pbnd, nil
}
func (n *ProtoNode) GetLinkedNode(ctx context.Context, ds format.DAGService, name string) (format.Node, error) {
	lnk, err := n.GetNodeLink(name)
	if err != nil {
		return nil, err
	}
	return lnk.GetNode(ctx, ds)
}
func (n *ProtoNode) Copy() format.Node {
	nnode := new(ProtoNode)
	if len(n.data) > 0 {
		nnode.data = make([]byte, len(n.data))
		copy(nnode.data, n.data)
	}
	if len(n.links) > 0 {
		nnode.links = make([]*format.Link, len(n.links))
		copy(nnode.links, n.links)
	}
	nnode.builder = n.builder
	return nnode
}
func (n *ProtoNode) RawData() []byte {
	out, err := n.EncodeProtobuf(false)
	if err != nil {
		panic(err)
	}
	return out
}
func (n *ProtoNode) Data() []byte {
	return n.data
}
func (n *ProtoNode) SetData(d []byte) {
	n.encoded = nil
	n.cached = cid.Undef
	n.data = d
}
func (n *ProtoNode) UpdateNodeLink(name string, that *ProtoNode) (*ProtoNode, error) {
	newnode := n.Copy().(*ProtoNode)
	_ = newnode.RemoveNodeLink(name)  
	err := newnode.AddNodeLink(name, that)
	return newnode, err
}
func (n *ProtoNode) Size() (uint64, error) {
	b, err := n.EncodeProtobuf(false)
	if err != nil {
		return 0, err
	}
	s := uint64(len(b))
	for _, l := range n.links {
		s += l.Size
	}
	return s, nil
}
func (n *ProtoNode) Stat() (*format.NodeStat, error) {
	enc, err := n.EncodeProtobuf(false)
	if err != nil {
		return nil, err
	}
	cumSize, err := n.Size()
	if err != nil {
		return nil, err
	}
	return &format.NodeStat{
		Hash:           n.Cid().String(),
		NumLinks:       len(n.links),
		BlockSize:      len(enc),
		LinksSize:      len(enc) - len(n.data),  
		DataSize:       len(n.data),
		CumulativeSize: int(cumSize),
	}, nil
}
func (n *ProtoNode) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"node": n.String(),
	}
}
func (n *ProtoNode) UnmarshalJSON(b []byte) error {
	s := struct {
		Data  []byte         `json:"data"`
		Links []*format.Link `json:"links"`
	}{}
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	n.data = s.Data
	n.links = s.Links
	return nil
}
func (n *ProtoNode) MarshalJSON() ([]byte, error) {
	out := map[string]interface{}{
		"data":  n.data,
		"links": n.links,
	}
	return json.Marshal(out)
}
func (n *ProtoNode) Cid() cid.Cid {
	if n.encoded != nil && n.cached.Defined() {
		return n.cached
	}
	c, err := n.CidBuilder().Sum(n.RawData())
	if err != nil {
		err = fmt.Errorf("invalid CID of length %d: %x: %v", len(n.RawData()), n.RawData(), err)
		panic(err)
	}
	n.cached = c
	return c
}
func (n *ProtoNode) String() string {
	return n.Cid().String()
}
func (n *ProtoNode) Multihash() mh.Multihash {
	_, err := n.EncodeProtobuf(false)
	if err != nil {
		panic(err)
	}
	return n.cached.Hash()
}
func (n *ProtoNode) Links() []*format.Link {
	return n.links
}
func (n *ProtoNode) SetLinks(links []*format.Link) {
	n.links = links
}
func (n *ProtoNode) Resolve(path []string) (interface{}, []string, error) {
	return n.ResolveLink(path)
}