func FaiToReferenceLengths(index io.Reader) (map[string]uint64, error) {
	newIndexed, err := NewIndexed(nil, index)
	if err != nil {
		return nil, err
	}
	newMap := make(map[string]uint64)
	for _, ref := range newIndexed.SeqNames() {
		refLength, err := newIndexed.Len(ref)
		if err != nil {
			return nil, err
		}
		newMap[ref] = refLength
	}
	return newMap, nil
}
FaiToReferenceLengths reads in a fasta fai file and returns a map of
reference name to reference length. This doesn't require reading in the fasta
itself.
package fasta
import (
	"bufio"
	"fmt"
	"io"
	"regexp"
	"sort"
	"strconv"
	"sync"
	"github.com/grailbio/base/must"
	"github.com/grailbio/bio/biosimd"
)
type indexEntry struct {
	name      string
	length    uint64
	offset    uint64
	lineBase  uint64
	lineWidth uint64
}
var indexRegExp = regexp.MustCompile(`(\S+)\t(\d+)\t(\d+)\t(\d+)\t(\d+)`)
type indexedFasta struct {
	seqs      map[string]indexEntry
	seqNames  []string  
	opts      opts
	reader    io.ReadSeeker
	bufOff    int64
	buf       []byte  
	resultBuf []byte  
	mutex     sync.Mutex
}
func NewIndexed(fasta io.ReadSeeker, index io.Reader, opts ...Opt) (Fasta, error) {
	entries, err := parseIndex(index)
	if err != nil {
		return nil, err
	}
	return newLazyIndexed(fasta, entries, makeOpts(opts...))
}
func newLazyIndexed(fasta io.ReadSeeker, index []indexEntry, parsedOpts opts) (Fasta, error) {
	f := indexedFasta{
		seqs:   make(map[string]indexEntry),
		reader: fasta,
		opts:   parsedOpts,
	}
	for _, entry := range index {
		f.seqs[entry.name] = entry
	}
	f.seqNames = make([]string, 0, len(f.seqs))
	for seqName := range f.seqs {
		f.seqNames = append(f.seqNames, seqName)
	}
	sort.SliceStable(f.seqNames, func(i, j int) bool {
		return f.seqs[f.seqNames[i]].offset < f.seqs[f.seqNames[j]].offset
	})
	return &f, nil
}
func parseIndex(r io.Reader) ([]indexEntry, error) {
	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanLines)
	var entries []indexEntry
	for scanner.Scan() {
		matches := indexRegExp.FindStringSubmatch(scanner.Text())
		if len(matches) != 6 {
			return nil, fmt.Errorf("Invalid index line: %s", scanner.Text())
		}
		ent := indexEntry{}
		ent.name = matches[1]
		var err error
		ent.length, err = strconv.ParseUint(matches[2], 10, 64)
		must.Nil(err)
		ent.offset, err = strconv.ParseUint(matches[3], 10, 64)
		must.Nil(err)
		ent.lineBase, err = strconv.ParseUint(matches[4], 10, 64)
		must.Nil(err)
		ent.lineWidth, err = strconv.ParseUint(matches[5], 10, 64)
		must.Nil(err)
		entries = append(entries, ent)
	}
	return entries, nil
}