func UnclippedFivePrimePosition(record *sam.Record) int {
	if IsReversedRead(record) {
		return UnclippedEnd(record)
	}
	return UnclippedStart(record)
}
UnclippedFivePrimePosition returns the unclipped 5' position of
record.
package bam
import (
	"fmt"
	"github.com/grailbio/hts/sam"
)
func IsPaired(record *sam.Record) bool {
	return record.Flags&sam.Paired != 0
}
func IsProperPair(record *sam.Record) bool {
	return record.Flags&sam.ProperPair != 0
}
func IsUnmapped(record *sam.Record) bool {
	return record.Flags&sam.Unmapped != 0
}
func IsMateUnmapped(record *sam.Record) bool {
	return record.Flags&sam.MateUnmapped != 0
}
func IsReverse(record *sam.Record) bool {
	return record.Flags&sam.Reverse != 0
}
func IsMateReverse(record *sam.Record) bool {
	return record.Flags&sam.MateReverse != 0
}
func IsRead1(record *sam.Record) bool {
	return record.Flags&sam.Read1 != 0
}
func IsRead2(record *sam.Record) bool {
	return record.Flags&sam.Read2 != 0
}
func IsSecondary(record *sam.Record) bool {
	return record.Flags&sam.Secondary != 0
}
func IsQCFail(record *sam.Record) bool {
	return record.Flags&sam.QCFail != 0
}
func IsDuplicate(record *sam.Record) bool {
	return record.Flags&sam.Duplicate != 0
}
func IsLinearDuplicate(record *sam.Record) bool {
	dupType, err := record.LinearDup()
	if err != nil {
		panic(err)
	}
	return dupType == sam.LinearDuplicate
}
func IsSupplementary(record *sam.Record) bool {
	return record.Flags&sam.Supplementary != 0
}
func IsPrimary(record *sam.Record) bool {
	return record.Flags&sam.Secondary == 0 && record.Flags&sam.Supplementary == 0
}
func HasNoMappedMate(record *sam.Record) bool {
	return (record.Flags&sam.Paired) == 0 || (record.Flags&sam.MateUnmapped) != 0
}
func ClearAuxTags(r *sam.Record, tagsToRemove []sam.Tag) {
	found := 0
	for i := range r.AuxFields {
		tag := r.AuxFields[i].Tag()
		for _, toRemove := range tagsToRemove {
			if tag == toRemove {
				found++
			}
		}
	}
	if found > 0 {
		newAux := make([]sam.Aux, len(r.AuxFields)-found)
		size := 0
		for i := range r.AuxFields {
			tag := r.AuxFields[i].Tag()
			keepAux := true
			for _, toRemove := range tagsToRemove {
				if tag == toRemove {
					keepAux = false
					break
				}
			}
			if keepAux {
				newAux[size] = r.AuxFields[i]
				size++
			}
		}
		r.AuxFields = newAux
	}
}
type StrandType int
const (
	StrandNone StrandType = iota
	StrandFwd
	StrandRev
)
func GetStrand(flags sam.Flags) StrandType {
	maskedFlag := flags & (sam.Unmapped | sam.Reverse | sam.Read1 | sam.Read2)
	if (maskedFlag == sam.Read1) || (maskedFlag == (sam.Reverse | sam.Read2)) {
		return StrandFwd
	}
	if (maskedFlag == sam.Read2) || (maskedFlag == (sam.Reverse | sam.Read1)) {
		return StrandRev
	}
	return StrandNone
}
func IsReversedRead(record *sam.Record) bool {
	return (record.Flags & sam.Reverse) != 0
}
func IsQCFailed(record *sam.Record) bool {
	return (record.Flags & sam.QCFail) != 0
}
func LeftClipDistance(record *sam.Record) int {
	total := 0
	for _, op := range record.Cigar {
		if op.Type() == sam.CigarSoftClipped || op.Type() == sam.CigarHardClipped {
			total += op.Len()
		} else {
			break
		}
	}
	return total
}
func RightClipDistance(record *sam.Record) int {
	total := 0
	for i := len(record.Cigar) - 1; i >= 0; i-- {
		op := record.Cigar[i]
		if op.Type() == sam.CigarSoftClipped || op.Type() == sam.CigarHardClipped {
			total += op.Len()
		} else {
			break
		}
	}
	return total
}
func FivePrimeClipDistance(record *sam.Record) int {
	if IsReversedRead(record) {
		return RightClipDistance(record)
	}
	return LeftClipDistance(record)
}
func UnclippedStart(record *sam.Record) int {
	return record.Start() - LeftClipDistance(record)
}
func UnclippedEnd(record *sam.Record) int {
	unclippedEnd := record.End() + RightClipDistance(record) - 1
	if unclippedEnd < record.Start() {
		panic(fmt.Sprintf("unclippedEnd is less than start: %d < %d for %s",
			unclippedEnd, record.Start(), record.Name))
	}
	return unclippedEnd
}