func (msgs *Messages) Offsets() ([]int, error) {
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return nil, err
		}
	}
	return msgs.offsets, nil
}
Offsets returns the offset data for these messages.
package model
import (
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"log"
)
const MESSAGE_OVERHEAD = 1 + 4 + 8 + 4
const MESSAGE_VERSION_OFFEST = 0
const MESSAGE_LENGTH_OFFSET = MESSAGE_VERSION_OFFEST + 1
const MESSAGE_TERM_OFFSET = MESSAGE_LENGTH_OFFSET + 4
const MESSAGE_CRC_OFFSET = MESSAGE_TERM_OFFSET + 8
var ERR_UNSUPPORTED_MESSAGE_FORMAT = errors.New("Unsupported message format")
var ERR_CRC_MISMATCH = errors.New("CRC check on message payload failed.")
var EMPTY_MESSAGES = Messages{}
type Messages struct {
	Count int
	Data  []byte
	offsets []int
	indexed bool
}
type MessageProvider interface {
	Messages() [][]byte
}
type MessageProviders []MessageProvider
func MessagesFromReader(r io.Reader, targetBytes int) (result Messages, readByteCount int, err error) {
	result = Messages{}
	if targetBytes < MESSAGE_OVERHEAD {
		targetBytes = MESSAGE_OVERHEAD + 1024
	}
	buffer := make([]byte, targetBytes)
	result.Data = buffer
	readByteCount, err = io.ReadFull(r, result.Data)
	if err != nil && err != io.ErrUnexpectedEOF {
		return result, readByteCount, err
	}
	result.Data = result.Data[:readByteCount]
	countErr := result.countMessages(true)
	if countErr != nil {
		return result, readByteCount, countErr
	}
	if result.Count < 1 && readByteCount >= MESSAGE_OVERHEAD {
		log.Printf("INFO: Having to read additional data in order to retrieve at least one message (%v bytes requested, %v read, data len %v)\n", targetBytes, readByteCount, len(result.Data))
		length := int32(binary.LittleEndian.Uint32(buffer[MESSAGE_LENGTH_OFFSET:]))
		newTarget := int(length) + MESSAGE_OVERHEAD
		remainderToRead := newTarget - readByteCount
		if remainderToRead > 0 {
			newData := make([]byte, newTarget)
			copy(newData, buffer[:readByteCount])
			newByteCount, err := io.ReadFull(r, newData[readByteCount:])
			readByteCount += newByteCount
			result.Data = newData
			if err != nil {
				return result, readByteCount, nil
			}
			countErr = result.countMessages(true)
			if countErr != nil {
				return result, readByteCount, countErr
			}
			if result.Count > 0 {
				log.Printf("Additional read to retrieve message worked - message retrieved.\n")
			}
		}
	}
	return result, readByteCount, nil
}
func (msgs *Messages) GetCount() int {
	return msgs.Count
}
func (msgs *Messages) forEachMessage(action func(msgIndex int, msgOffset int) bool) error {
	dlen := len(msgs.Data) - MESSAGE_OVERHEAD
	localCount := 0
	for msgOffset := 0; msgOffset <= dlen; {
		if msgs.Data[msgOffset] != 0 {
			return ERR_UNSUPPORTED_MESSAGE_FORMAT
		}
		length := int32(binary.LittleEndian.Uint32(msgs.Data[msgOffset+MESSAGE_LENGTH_OFFSET:]))
		if msgOffset+MESSAGE_OVERHEAD+int(length) <= len(msgs.Data) {
			if !action(localCount, msgOffset) {
				return nil
			}
		} else {
			msgs.Data = msgs.Data[:msgOffset]
			break
		}
		localCount++
		msgOffset += MESSAGE_OVERHEAD + int(length)
	}
	return nil
}
func (msgs *Messages) countMessages(crcCheck bool) error {
	msgs.Count = 0
	crcError := false
	msgs.offsets = make([]int, 0)
	err := msgs.forEachMessage(func(forIndex int, offset int) bool {
		if crcCheck {
			length := int32(binary.LittleEndian.Uint32(msgs.Data[offset+MESSAGE_LENGTH_OFFSET:]))
			CRC := uint32(binary.LittleEndian.Uint32(msgs.Data[offset+MESSAGE_CRC_OFFSET:]))
			actualCRC := crc32.ChecksumIEEE(msgs.Data[offset+MESSAGE_OVERHEAD : offset+MESSAGE_OVERHEAD+int(length)])
			if CRC != actualCRC {
				crcError = true
			}
		}
		msgs.Count++
		msgs.offsets = append(msgs.offsets, offset)
		return true
	})
	if crcError {
		return ERR_CRC_MISMATCH
	}
	msgs.indexed = true
	return err
}
func (msgs *Messages) GetMessageTerm(index int) (int64, error) {
	var term int64
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return 0, err
		}
	}
	offset := msgs.offsets[index]
	term = int64(binary.LittleEndian.Uint64(msgs.Data[offset+MESSAGE_TERM_OFFSET:]))
	return term, nil
}
func (msgs *Messages) SetMessageTerm(newTerm int64) error {
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return err
		}
	}
	for _, offset := range msgs.offsets {
		binary.LittleEndian.PutUint64(msgs.Data[offset+MESSAGE_TERM_OFFSET:], uint64(newTerm))
	}
	return nil
}
func (msgs *Messages) Write(w io.Writer) (int, error) {
	written, err := w.Write(msgs.Data)
	if err != nil {
		return 0, err
	}
	return written, nil
}
func (msgs *Messages) Slice(fromMessageIndex int, toMessageIndex int) (Messages, error) {
	var dataSliceStart int
	var endOfSlice int
	result := Messages{}
	if toMessageIndex == fromMessageIndex {
		return result, nil
	}
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return result, err
		}
	}
	dataSliceStart = msgs.offsets[fromMessageIndex]
	if toMessageIndex >= msgs.Count {
		endOfSlice = len(msgs.Data)
	} else {
		endOfSlice = msgs.offsets[toMessageIndex]
	}
	result.Data = msgs.Data[dataSliceStart:endOfSlice]
	result.offsets = make([]int, toMessageIndex-fromMessageIndex)
	newIndex := 0
	for i := fromMessageIndex; i < toMessageIndex; i++ {
		result.offsets[newIndex] = msgs.offsets[i] - dataSliceStart
		newIndex++
	}
	result.indexed = true
	result.Count = toMessageIndex - fromMessageIndex
	return result, nil
}
func (msgs *Messages) Join(extraMessages Messages) (Messages, error) {
	newMessages := Messages{}
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return newMessages, err
		}
	}
	if !extraMessages.indexed {
		err := extraMessages.countMessages(false)
		if err != nil {
			return newMessages, err
		}
	}
	newLength := len(msgs.Data) + len(extraMessages.Data)
	newMessages.Data = make([]byte, newLength)
	copy(newMessages.Data, msgs.Data)
	copy(newMessages.Data[len(msgs.Data):], extraMessages.Data)
	newMessages.offsets = make([]int, msgs.Count, msgs.Count+extraMessages.Count)
	copy(newMessages.offsets, msgs.offsets)
	origLen := len(msgs.Data)
	for _, extraOffset := range extraMessages.offsets {
		newMessages.offsets = append(newMessages.offsets, extraOffset+origLen)
	}
	newMessages.Count = msgs.Count + extraMessages.Count
	newMessages.indexed = true
	return newMessages, nil
}
func (msgs *Messages) Payloads() ([][]byte, error) {
	results := make([][]byte, msgs.Count)
	if !msgs.indexed {
		err := msgs.countMessages(false)
		if err != nil {
			return results, err
		}
	}
	for i, offset := range msgs.offsets {
		var endOfMsg int
		if (i + 1) == msgs.Count {
			endOfMsg = len(msgs.Data)
		} else {
			endOfMsg = msgs.offsets[i+1]
		}
		results[i] = msgs.Data[offset+MESSAGE_OVERHEAD : endOfMsg]
	}
	return results, nil
}
func (msgs *Messages) RawData() []byte {
	return msgs.Data
}