func (f *recordingFile) WriteRecordingFile() {
	outRecordDecls := make([]string, 0, len(f.recordingDecls)+len(f.addRecordings))
	outRecordingDecls := make(map[string]string)
	hashToNumMap := make(map[hashValue]int)
	addRecordDecl := func(recordDecl string) int {
		if len(recordDecl) > MaxRecordingSize {
			panic(errors.New("recording exceeds copyist.MaxRecordingSize and cannot be written"))
		}
		hashVal := f.hashStr(recordDecl)
		num, ok := hashToNumMap[hashVal]
		if !ok {
			num = len(outRecordDecls)
			hashToNumMap[hashVal] = num
			outRecordDecls = append(outRecordDecls, recordDecl)
		}
		return num
	}
	formatRecording := func(recordNums []int) string {
		f.scratch.Reset()
		for i, num := range recordNums {
			if i != 0 {
				f.scratch.WriteByte(',')
			}
			f.scratch.WriteString(strconv.Itoa(num + 1))
		}
		return f.scratch.String()
	}
	for recordingName, recordingDecl := range f.recordingDecls {
		if _, ok := f.addRecordings[recordingName]; ok {
			continue
		}
		oldRecordNums := f.parseRecordingDecl(recordingDecl)
		newRecordNums := make([]int, len(oldRecordNums))
		for i, num := range oldRecordNums {
			recordDecl, ok := f.recordDecls[num]
			if !ok {
				panic(fmt.Errorf("record with number %d must exist", num))
			}
			newRecordNums[i] = addRecordDecl(recordDecl)
		}
		outRecordingDecls[recordingName] = formatRecording(newRecordNums)
	}
	for recordingName, recording := range f.addRecordings {
		newRecordNums := make([]int, len(recording))
		for i, record := range recording {
			newRecordNums[i] = addRecordDecl(f.formatRecord(record))
		}
		outRecordingDecls[recordingName] = formatRecording(newRecordNums)
	}
	f.scratch.Reset()
	for num, recordDecl := range outRecordDecls {
		f.scratch.WriteString(strconv.Itoa(num + 1))
		f.scratch.WriteByte('=')
		f.scratch.WriteString(recordDecl)
		f.scratch.WriteByte('\n')
	}
	f.scratch.WriteByte('\n')
	for recordingName, recordingDecl := range outRecordingDecls {
		f.scratch.WriteString(strconv.Quote(recordingName))
		f.scratch.WriteByte('=')
		f.scratch.WriteString(recordingDecl)
		f.scratch.WriteByte('\n')
	}
	dirName := path.Dir(f.pathName)
	if _, err := os.Stat(dirName); os.IsNotExist(err) {
		if err := os.MkdirAll(dirName, 0777); err != nil {
			panic(err)
		}
	}
	if err := ioutil.WriteFile(f.pathName, f.scratch.Bytes(), 0666); err != nil {
		panic(err)
	}
}
WriteRecordingFile writes all recordings to the recording file in the copyist
recording file format. All recordings buffered in memory will be written,
with any recordings added by AddRecording overriding existing recordings.
Only record declarations that are used by the written set of recordings will
be written to disk.
package copyist
import (
	"bufio"
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"hash"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)
type hashValue [md5.Size]byte
type recordingFile struct {
	pathName string
	recordDecls map[int]string
	recordingDecls map[string]string
	addRecordings map[string]recording
	md5Hasher hash.Hash
	scratch bytes.Buffer
}
func newRecordingFile(pathName string) *recordingFile {
	return &recordingFile{pathName: pathName, md5Hasher: md5.New()}
}
func (f *recordingFile) GetRecording(recordingName string) recording {
	recordingDecl, ok := f.recordingDecls[recordingName]
	if !ok {
		return nil
	}
	nums := f.parseRecordingDecl(recordingDecl)
	recording := make(recording, len(nums))
	for i := range nums {
		rec := f.parseRecord(nums[i])
		recording[i] = rec
	}
	return recording
}
func (f *recordingFile) AddRecording(recordingName string, newRecording recording) {
	if f.addRecordings == nil {
		f.addRecordings = make(map[string]recording)
	}
	f.addRecordings[recordingName] = newRecording
}