package riffbin_test

import (
	"bytes"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"hash/crc32"
	"io"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"github.com/karupanerura/riffbin"
)

type callbackReader func([]byte) (int, error)

func (r callbackReader) Read(p []byte) (int, error) {
	return r(p)
}

var errOverLimit = errors.New("over limit")

type limitedWriter struct {
	N int64
	W io.Writer
}

func (w *limitedWriter) Write(p []byte) (int, error) {
	if w.N == 0 {
		return 0, errOverLimit
	}

	over := false
	if int64(len(p)) > w.N {
		p = p[:w.N]
		over = true
	}

	n, err := w.W.Write(p)
	if over {
		return n, errOverLimit
	}
	if err != nil {
		return n, err
	}

	w.N -= int64(n)
	return n, nil
}

type pureWriteSeeker struct {
	W io.WriteSeeker
}

func (w *pureWriteSeeker) Write(p []byte) (int, error) {
	return w.W.Write(p)
}

func (w *pureWriteSeeker) Seek(offset int64, whence int) (int64, error) {
	return w.W.Seek(offset, whence)
}

func TestCompletedChunkWriter(t *testing.T) {
	t.Parallel()
	t.Run("Basic", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '1'},
					Payload: []byte("sample"),
				},
			},
		}

		var buf bytes.Buffer
		n, err := riffbin.NewCompletedChunkWriter(&buf).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}

		expected := []byte{
			0x52, 0x49, 0x46, 0x46, 
			0x12, 0x00, 0x00, 0x00, 
			0x54, 0x45, 0x53, 0x54, 
			0x45, 0x4e, 0x54, 0x31, 
			0x06, 0x00, 0x00, 0x00, 
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 
		}
		if got := buf.Bytes(); !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("UnexpectedIncompleteError", func(t *testing.T) {
		t.Parallel()
		n, err := riffbin.NewCompletedChunkWriter(io.Discard).Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if !errors.Is(err, riffbin.ErrUnexpectedIncompleteChunk) {
			t.Fatalf("unexpected error: %v", err)
		}
		if n != 20 {
			t.Fatalf("should be 20 bytes are written but got: %d", n)
		}
	})

	t.Run("Complex", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '1'},
					Payload: []riffbin.Chunk{
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '1'},
							Payload: []byte{0x01},
						},
						&riffbin.ListChunk{
							ListType: [4]byte{'L', 'S', 'T', '2'},
							Payload: []riffbin.Chunk{
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '2'},
									Payload: []byte{0x01, 0x02},
								},
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '3'},
									Payload: []byte{0x01, 0x02, 0x03},
								},
							},
						},
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '4'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04},
						},
					},
				},
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '5'},
					Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '3'},
					Payload:  []riffbin.Chunk{},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '4'},
					Payload: []riffbin.Chunk{
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '6'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
						},
					},
				},
			},
		}

		var buf bytes.Buffer
		c := crc32.NewIEEE()
		n, err := riffbin.NewCompletedChunkWriter(io.MultiWriter(&buf, c)).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}
		if s := c.Sum32(); s != 3366069976 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("Wave", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'W', 'A', 'V', 'E'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID: [4]byte{'f', 'm', 't', ' '},
					Payload: []byte{
						0x01, 0x00, 
						0x01, 0x00, 
						0x44, 0xAC, 0x00, 0x00, 
						0x44, 0xAC, 0x00, 0x00, 
						0x01, 0x00, 
						0x08, 0x00, 
					},
				},
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'d', 'a', 't', 'a'},
					Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
				},
			},
		}

		var buf bytes.Buffer
		c := crc32.NewIEEE()
		n, err := riffbin.NewCompletedChunkWriter(io.MultiWriter(&buf, c)).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}
		if s := c.Sum32(); s != 1759927271 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("EmulateIOError", func(t *testing.T) {
		t.Parallel()
		for lim := int64(0); lim < 2044; lim++ {
			n, err := riffbin.NewCompletedChunkWriter(&limitedWriter{N: lim, W: io.Discard}).Write(&riffbin.RIFFChunk{
				FormType: [4]byte{'W', 'A', 'V', 'E'},
				Payload: []riffbin.Chunk{
					&riffbin.OnMemorySubChunk{
						ID: [4]byte{'f', 'm', 't', ' '},
						Payload: []byte{
							0x01, 0x00, 
							0x01, 0x00, 
							0x44, 0xAC, 0x00, 0x00, 
							0x44, 0xAC, 0x00, 0x00, 
							0x01, 0x00, 
							0x08, 0x00, 
						},
					},
					&riffbin.OnMemorySubChunk{
						ID:      [4]byte{'d', 'a', 't', 'a'},
						Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
					},
				},
			})

			if !errors.Is(err, errOverLimit) {
				t.Errorf("unexpected error: %v", err)
			}
			if n != lim {
				t.Errorf("wrote over limit: %d", n)
			}
		}
	})
}

func TestInompletedChunkWriter(t *testing.T) {
	t.Parallel()
	t.Run("Basic", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		if pos, err := f.Seek(0, io.SeekCurrent); err != nil {
			t.Fatal(err)
		} else if pos != n {
			t.Errorf("unexpected seek position: %d", pos)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		expected := []byte{
			0x52, 0x49, 0x46, 0x46, 
			0x12, 0x00, 0x00, 0x00, 
			0x54, 0x45, 0x53, 0x54, 
			0x45, 0x4e, 0x54, 0x31, 
			0x06, 0x00, 0x00, 0x00, 
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Seek", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(&pureWriteSeeker{W: f})
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		if pos, err := f.Seek(0, io.SeekCurrent); err != nil {
			t.Fatal(err)
		} else if pos != n {
			t.Errorf("unexpected seek position: %d", pos)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		expected := []byte{
			0x52, 0x49, 0x46, 0x46, 
			0x12, 0x00, 0x00, 0x00, 
			0x54, 0x45, 0x53, 0x54, 
			0x45, 0x4e, 0x54, 0x31, 
			0x06, 0x00, 0x00, 0x00, 
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Mixed", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '1'},
					Payload: []byte("sample"),
				},
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '2'}, strings.NewReader("foo")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		expected := []byte{
			0x52, 0x49, 0x46, 0x46, 
			0x1D, 0x00, 0x00, 0x00, 
			0x54, 0x45, 0x53, 0x54, 
			0x45, 0x4e, 0x54, 0x31, 
			0x06, 0x00, 0x00, 0x00, 
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 
			0x45, 0x4e, 0x54, 0x32, 
			0x03, 0x00, 0x00, 0x00, 
			0x66, 0x6f, 0x6f, 
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("ComplexMixed", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '1'},
					Payload: []riffbin.Chunk{
						riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, bytes.NewReader([]byte{0x01})),
						&riffbin.ListChunk{
							ListType: [4]byte{'L', 'S', 'T', '2'},
							Payload: []riffbin.Chunk{
								riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '2'}, bytes.NewReader([]byte{0x01, 0x02})),
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '3'},
									Payload: []byte{0x01, 0x02, 0x03},
								},
							},
						},
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '4'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04},
						},
					},
				},
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '5'}, bytes.NewReader([]byte{0x01, 0x02, 0x03, 0x04, 0x05})),
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '3'},
					Payload:  []riffbin.Chunk{},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '4'},
					Payload: []riffbin.Chunk{
						riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '6'}, bytes.NewReader([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06})),
					},
				},
			},
		})
		if err != nil {
			t.Fatal(err)

		}
		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		got, err := os.ReadFile(f.Name())
		if err != nil {
			t.Fatal(err)
		}
		if s := crc32.ChecksumIEEE(got); s != 3366069976 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Wave", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'W', 'A', 'V', 'E'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID: [4]byte{'f', 'm', 't', ' '},
					Payload: []byte{
						0x01, 0x00, 
						0x01, 0x00, 
						0x44, 0xAC, 0x00, 0x00, 
						0x44, 0xAC, 0x00, 0x00, 
						0x01, 0x00, 
						0x08, 0x00, 
					},
				},
				riffbin.NewIncompleteSubChunk([4]byte{'d', 'a', 't', 'a'}, callbackReader(func() func(p []byte) (n int, err error) {
					max := 20 * int(math.Ceil(44100/440))
					i := 0
					return func(p []byte) (n int, err error) {
						for n < len(p) && i < max {
							p[n] = byte(math.Floor(255.0 * (1.0 + math.Sin(2.0*math.Pi*float64(i)/(44100/440))) / 2.0))
							n++
							i++
						}
						if n == 0 {
							err = io.EOF
						}
						return
					}
				}())),
			},
		})
		if err != nil {
			t.Fatal(err)
		}
		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		got, err := os.ReadFile(f.Name())
		if err != nil {
			t.Fatal(err)
		}
		if s := crc32.ChecksumIEEE(got); s != 1759927271 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(got))
		}
	})
}

func ExampleCompletedChunkWriter_Write() {
	encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
	_, err := riffbin.NewCompletedChunkWriter(encoder).Write(&riffbin.RIFFChunk{
		FormType: [4]byte{'W', 'A', 'V', 'E'},
		Payload: []riffbin.Chunk{
			&riffbin.OnMemorySubChunk{
				ID: [4]byte{'f', 'm', 't', ' '},
				Payload: []byte{
					0x01, 0x00, 
					0x01, 0x00, 
					0x44, 0xAC, 0x00, 0x00, 
					0x44, 0xAC, 0x00, 0x00, 
					0x01, 0x00, 
					0x08, 0x00, 
				},
			},

			&riffbin.OnMemorySubChunk{
				ID:      [4]byte{'d', 'a', 't', 'a'},
				Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
			},
		},
	})
	if err != nil {
		panic(err)
	}

	err = encoder.Close()
	if err != nil {
		panic(err)
	}

}

func ExampleIncompleteChunkWriter_Write() {
	f, err := os.CreateTemp("", "riffbin")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	w, err := riffbin.NewIncompleteChunkWriter(f)
	if err != nil {
		panic(err)
	}

	_, err = w.Write(&riffbin.RIFFChunk{
		FormType: [4]byte{'W', 'A', 'V', 'E'},
		Payload: []riffbin.Chunk{
			&riffbin.OnMemorySubChunk{
				ID: [4]byte{'f', 'm', 't', ' '},
				Payload: []byte{
					0x01, 0x00, 
					0x01, 0x00, 
					0x44, 0xAC, 0x00, 0x00, 
					0x44, 0xAC, 0x00, 0x00, 
					0x01, 0x00, 
					0x08, 0x00, 
				},
			},

			riffbin.NewIncompleteSubChunk([4]byte{'d', 'a', 't', 'a'}, callbackReader(func() func(p []byte) (n int, err error) {
				max := 1000 * int(math.Ceil(44100/440))
				i := 0
				return func(p []byte) (n int, err error) {
					for n < len(p) && i < max {
						p[n] = byte(math.Floor((float64(i) / float64(max)) * 255.0 * (1.0 + math.Sin(2.0*math.Pi*float64(i)/(44100/440))) / 2.0))
						n++
						i++
					}
					if n == 0 {
						err = io.EOF
					}
					return
				}
			}())),
		},
	})
	if err != nil {
		panic(err)
	}

	if os.Getenv("DEBUG_TEST_PLAY") != "" && runtime.GOOS == "darwin" {
		err = exec.Command("afplay", f.Name()).Run()
		if err != nil {
			panic(err)
		}
	}

}
package riffbin_test

import (
	"bytes"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"hash/crc32"
	"io"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"github.com/karupanerura/riffbin"
)

type callbackReader func([]byte) (int, error)

func (r callbackReader) Read(p []byte) (int, error) {
	return r(p)
}

var errOverLimit = errors.New("over limit")

type limitedWriter struct {
	N int64
	W io.Writer
}

func (w *limitedWriter) Write(p []byte) (int, error) {
	if w.N == 0 {
		return 0, errOverLimit
	}

	over := false
	if int64(len(p)) > w.N {
		p = p[:w.N]
		over = true
	}

	n, err := w.W.Write(p)
	if over {
		return n, errOverLimit
	}
	if err != nil {
		return n, err
	}

	w.N -= int64(n)
	return n, nil
}

// to hide for io.WriterAt
type pureWriteSeeker struct {
	W io.WriteSeeker
}

func (w *pureWriteSeeker) Write(p []byte) (int, error) {
	return w.W.Write(p)
}

func (w *pureWriteSeeker) Seek(offset int64, whence int) (int64, error) {
	return w.W.Seek(offset, whence)
}

func TestCompletedChunkWriter(t *testing.T) {
	t.Parallel()
	t.Run("Basic", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '1'},
					Payload: []byte("sample"),
				},
			},
		}

		var buf bytes.Buffer
		n, err := riffbin.NewCompletedChunkWriter(&buf).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}

		expected := []byte{
			0x52, 0x49, 0x46, 0x46, // id (RIFF)
			0x12, 0x00, 0x00, 0x00, // body size
			0x54, 0x45, 0x53, 0x54, // type (TEST)
			0x45, 0x4e, 0x54, 0x31, // id (ENT1)
			0x06, 0x00, 0x00, 0x00, // body size
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, // "sample"
		}
		if got := buf.Bytes(); !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("UnexpectedIncompleteError", func(t *testing.T) {
		t.Parallel()
		n, err := riffbin.NewCompletedChunkWriter(io.Discard).Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if !errors.Is(err, riffbin.ErrUnexpectedIncompleteChunk) {
			t.Fatalf("unexpected error: %v", err)
		}
		if n != 20 {
			t.Fatalf("should be 20 bytes are written but got: %d", n)
		}
	})

	t.Run("Complex", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '1'},
					Payload: []riffbin.Chunk{
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '1'},
							Payload: []byte{0x01},
						},
						&riffbin.ListChunk{
							ListType: [4]byte{'L', 'S', 'T', '2'},
							Payload: []riffbin.Chunk{
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '2'},
									Payload: []byte{0x01, 0x02},
								},
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '3'},
									Payload: []byte{0x01, 0x02, 0x03},
								},
							},
						},
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '4'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04},
						},
					},
				},
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '5'},
					Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '3'},
					Payload:  []riffbin.Chunk{},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '4'},
					Payload: []riffbin.Chunk{
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '6'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
						},
					},
				},
			},
		}

		var buf bytes.Buffer
		c := crc32.NewIEEE()
		n, err := riffbin.NewCompletedChunkWriter(io.MultiWriter(&buf, c)).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}
		if s := c.Sum32(); s != 3366069976 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("Wave", func(t *testing.T) {
		t.Parallel()
		riffChunk := &riffbin.RIFFChunk{
			FormType: [4]byte{'W', 'A', 'V', 'E'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID: [4]byte{'f', 'm', 't', ' '},
					Payload: []byte{
						0x01, 0x00, // Compression Code (Linear PCM)
						0x01, 0x00, // Number of channels (Monoral)
						0x44, 0xAC, 0x00, 0x00, // Sample rate (44.1Hz)
						0x44, 0xAC, 0x00, 0x00, // Average bytes per second (44.1Hz/Monoral)
						0x01, 0x00, // Block align (8bit/Monoral)
						0x08, 0x00, // Significant bits per sample (8bit)
					},
				},
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'d', 'a', 't', 'a'},
					Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
				},
			},
		}

		var buf bytes.Buffer
		c := crc32.NewIEEE()
		n, err := riffbin.NewCompletedChunkWriter(io.MultiWriter(&buf, c)).Write(riffChunk)
		if err != nil {
			t.Fatal(err)
		}
		if n != int64(buf.Len()) {
			t.Errorf("n should be %d but got %d", buf.Len(), n)
		}
		if s := c.Sum32(); s != 1759927271 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(buf.Bytes()))
		}

		t.Run("ReadFull", func(t *testing.T) {
			t.Parallel()
			if got, err := riffbin.ReadFull(&buf); err != nil {
				t.Fatal(err)
			} else if df := cmp.Diff(got, riffChunk, cmpopts.IgnoreUnexported(riffbin.OnMemorySubChunk{})); df != "" {
				t.Error(df)
			}
		})
	})

	t.Run("EmulateIOError", func(t *testing.T) {
		t.Parallel()
		for lim := int64(0); lim < 2044; lim++ {
			n, err := riffbin.NewCompletedChunkWriter(&limitedWriter{N: lim, W: io.Discard}).Write(&riffbin.RIFFChunk{
				FormType: [4]byte{'W', 'A', 'V', 'E'},
				Payload: []riffbin.Chunk{
					&riffbin.OnMemorySubChunk{
						ID: [4]byte{'f', 'm', 't', ' '},
						Payload: []byte{
							0x01, 0x00, // Compression Code (Linear PCM)
							0x01, 0x00, // Number of channels (Monoral)
							0x44, 0xAC, 0x00, 0x00, // Sample rate (44.1Hz)
							0x44, 0xAC, 0x00, 0x00, // Average bytes per second (44.1Hz/Monoral)
							0x01, 0x00, // Block align (8bit/Monoral)
							0x08, 0x00, // Significant bits per sample (8bit)
						},
					},
					&riffbin.OnMemorySubChunk{
						ID:      [4]byte{'d', 'a', 't', 'a'},
						Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
					},
				},
			})

			if !errors.Is(err, errOverLimit) {
				t.Errorf("unexpected error: %v", err)
			}
			if n != lim {
				t.Errorf("wrote over limit: %d", n)
			}
		}
	})
}

func TestInompletedChunkWriter(t *testing.T) {
	t.Parallel()
	t.Run("Basic", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		// check seek position
		if pos, err := f.Seek(0, io.SeekCurrent); err != nil {
			t.Fatal(err)
		} else if pos != n {
			t.Errorf("unexpected seek position: %d", pos)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		// check file size
		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		// check contents
		expected := []byte{
			0x52, 0x49, 0x46, 0x46, // id (RIFF)
			0x12, 0x00, 0x00, 0x00, // body size
			0x54, 0x45, 0x53, 0x54, // type (TEST)
			0x45, 0x4e, 0x54, 0x31, // id (ENT1)
			0x06, 0x00, 0x00, 0x00, // body size
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, // "sample"
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Seek", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(&pureWriteSeeker{W: f})
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, strings.NewReader("sample")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		// check seek position
		if pos, err := f.Seek(0, io.SeekCurrent); err != nil {
			t.Fatal(err)
		} else if pos != n {
			t.Errorf("unexpected seek position: %d", pos)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		// check file size
		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		// check contents
		expected := []byte{
			0x52, 0x49, 0x46, 0x46, // id (RIFF)
			0x12, 0x00, 0x00, 0x00, // body size
			0x54, 0x45, 0x53, 0x54, // type (TEST)
			0x45, 0x4e, 0x54, 0x31, // id (ENT1)
			0x06, 0x00, 0x00, 0x00, // body size
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, // "sample"
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Mixed", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID:      [4]byte{'E', 'N', 'T', '1'},
					Payload: []byte("sample"),
				},
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '2'}, strings.NewReader("foo")),
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		// check file size
		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		// check contents
		expected := []byte{
			0x52, 0x49, 0x46, 0x46, // id (RIFF)
			0x1D, 0x00, 0x00, 0x00, // body size
			0x54, 0x45, 0x53, 0x54, // type (TEST)
			0x45, 0x4e, 0x54, 0x31, // id (ENT1)
			0x06, 0x00, 0x00, 0x00, // body size
			0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, // "sample"
			0x45, 0x4e, 0x54, 0x32, // id (ENT2)
			0x03, 0x00, 0x00, 0x00, // body size
			0x66, 0x6f, 0x6f, // "foo"
		}
		if got, err := os.ReadFile(f.Name()); err != nil {
			t.Fatal(err)
		} else if !bytes.Equal(got, expected) {
			t.Error("unexpected bytes are written")
			t.Log(hex.Dump(got))
		}
	})

	t.Run("ComplexMixed", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'T', 'E', 'S', 'T'},
			Payload: []riffbin.Chunk{
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '1'},
					Payload: []riffbin.Chunk{
						riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '1'}, bytes.NewReader([]byte{0x01})),
						&riffbin.ListChunk{
							ListType: [4]byte{'L', 'S', 'T', '2'},
							Payload: []riffbin.Chunk{
								riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '2'}, bytes.NewReader([]byte{0x01, 0x02})),
								&riffbin.OnMemorySubChunk{
									ID:      [4]byte{'E', 'N', 'T', '3'},
									Payload: []byte{0x01, 0x02, 0x03},
								},
							},
						},
						&riffbin.OnMemorySubChunk{
							ID:      [4]byte{'E', 'N', 'T', '4'},
							Payload: []byte{0x01, 0x02, 0x03, 0x04},
						},
					},
				},
				riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '5'}, bytes.NewReader([]byte{0x01, 0x02, 0x03, 0x04, 0x05})),
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '3'},
					Payload:  []riffbin.Chunk{},
				},
				&riffbin.ListChunk{
					ListType: [4]byte{'L', 'S', 'T', '4'},
					Payload: []riffbin.Chunk{
						riffbin.NewIncompleteSubChunk([4]byte{'E', 'N', 'T', '6'}, bytes.NewReader([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06})),
					},
				},
			},
		})
		if err != nil {
			t.Fatal(err)

		}
		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		// check file size
		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		// check checksum
		got, err := os.ReadFile(f.Name())
		if err != nil {
			t.Fatal(err)
		}
		if s := crc32.ChecksumIEEE(got); s != 3366069976 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(got))
		}
	})

	t.Run("Wave", func(t *testing.T) {
		t.Parallel()
		f, err := os.CreateTemp("", "riffbin")
		if err != nil {
			t.Fatal(err)
		}
		defer os.Remove(f.Name())

		w, err := riffbin.NewIncompleteChunkWriter(f)
		if err != nil {
			t.Fatal(err)
		}

		n, err := w.Write(&riffbin.RIFFChunk{
			FormType: [4]byte{'W', 'A', 'V', 'E'},
			Payload: []riffbin.Chunk{
				&riffbin.OnMemorySubChunk{
					ID: [4]byte{'f', 'm', 't', ' '},
					Payload: []byte{
						0x01, 0x00, // Compression Code (Linear PCM)
						0x01, 0x00, // Number of channels (Monoral)
						0x44, 0xAC, 0x00, 0x00, // Sample rate (44.1Hz)
						0x44, 0xAC, 0x00, 0x00, // Average bytes per second (44.1Hz/Monoral)
						0x01, 0x00, // Block align (8bit/Monoral)
						0x08, 0x00, // Significant bits per sample (8bit)
					},
				},
				riffbin.NewIncompleteSubChunk([4]byte{'d', 'a', 't', 'a'}, callbackReader(func() func(p []byte) (n int, err error) {
					max := 20 * int(math.Ceil(44100/440))
					i := 0
					return func(p []byte) (n int, err error) {
						for n < len(p) && i < max {
							p[n] = byte(math.Floor(255.0 * (1.0 + math.Sin(2.0*math.Pi*float64(i)/(44100/440))) / 2.0))
							n++
							i++
						}
						if n == 0 {
							err = io.EOF
						}
						return
					}
				}())),
			},
		})
		if err != nil {
			t.Fatal(err)
		}
		err = f.Close()
		if err != nil {
			t.Fatal(err)
		}

		// check file size
		if stat, err := os.Stat(f.Name()); err != nil {
			t.Fatal(err)
		} else if stat.Size() != n {
			t.Errorf("n should be %d but got %d", stat.Size(), n)
		}

		// check checksum
		got, err := os.ReadFile(f.Name())
		if err != nil {
			t.Fatal(err)
		}
		if s := crc32.ChecksumIEEE(got); s != 1759927271 {
			t.Errorf("unexpected check sum: %d", s)
			t.Log(hex.Dump(got))
		}
	})
}

func ExampleCompletedChunkWriter_Write() {
	encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
	_, err := riffbin.NewCompletedChunkWriter(encoder).Write(&riffbin.RIFFChunk{
		FormType: [4]byte{'W', 'A', 'V', 'E'},
		Payload: []riffbin.Chunk{
			&riffbin.OnMemorySubChunk{
				ID: [4]byte{'f', 'm', 't', ' '},
				Payload: []byte{
					0x01, 0x00, // Compression Code (Linear PCM)
					0x01, 0x00, // Number of channels (Monoral)
					0x44, 0xAC, 0x00, 0x00, // Sample rate (44.1Hz)
					0x44, 0xAC, 0x00, 0x00, // Average bytes per second (44.1Hz/Monoral)
					0x01, 0x00, // Block align (8bit/Monoral)
					0x08, 0x00, // Significant bits per sample (8bit)
				},
			},
			// very short sin wave
			&riffbin.OnMemorySubChunk{
				ID:      [4]byte{'d', 'a', 't', 'a'},
				Payload: []byte{0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77, 0x7f, 0x87, 0x8f, 0x97, 0x9f, 0xa6, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd0, 0xd6, 0xdc, 0xe1, 0xe6, 0xeb, 0xef, 0xf2, 0xf6, 0xf8, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf2, 0xef, 0xeb, 0xe6, 0xe1, 0xdc, 0xd6, 0xd0, 0xca, 0xc3, 0xbc, 0xb5, 0xae, 0xa6, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x77, 0x6f, 0x67, 0x5f, 0x58, 0x50, 0x49, 0x42, 0x3b, 0x34, 0x2e, 0x28, 0x22, 0x1d, 0x18, 0x13, 0x0f, 0x0c, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0c, 0x0f, 0x13, 0x18, 0x1d, 0x22, 0x28, 0x2e, 0x34, 0x3b, 0x42, 0x49, 0x50, 0x58, 0x5f, 0x67, 0x6f, 0x77},
			},
		},
	})
	if err != nil {
		panic(err)
	}

	err = encoder.Close()
	if err != nil {
		panic(err)
	}

	// Output:
	// UklGRvQHAABXQVZFZm10IBAAAAABAAEARKwAAESsAAABAAgAZGF0YdAHAAB/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvd3+Hj5efpq61vMPK0Nbc4ebr7/L2+Pr8/f7//v38+vj28u/r5uHc1tDKw7y1rqafl4+Hf3dvZ19YUElCOzQuKCIdGBMPDAgGBAIBAAAAAQIEBggMDxMYHSIoLjQ7QklQWF9nb3d/h4+Xn6autbzDytDW3OHm6+/y9vj6/P3+//79/Pr49vLv6+bh3NbQysO8ta6mn5ePh393b2dfWFBJQjs0LigiHRgTDwwIBgQCAQAAAAECBAYIDA8TGB0iKC40O0JJUFhfZ293f4ePl5+mrrW8w8rQ1tzh5uvv8vb4+vz9/v/+/fz6+Pby7+vm4dzW0MrDvLWupp+Xj4d/d29nX1hQSUI7NC4oIh0YEw8MCAYEAgEAAAABAgQGCAwPExgdIiguNDtCSVBYX2dvdw==
}

func ExampleIncompleteChunkWriter_Write() {
	f, err := os.CreateTemp("", "riffbin")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	w, err := riffbin.NewIncompleteChunkWriter(f)
	if err != nil {
		panic(err)
	}

	_, err = w.Write(&riffbin.RIFFChunk{
		FormType: [4]byte{'W', 'A', 'V', 'E'},
		Payload: []riffbin.Chunk{
			&riffbin.OnMemorySubChunk{
				ID: [4]byte{'f', 'm', 't', ' '},
				Payload: []byte{
					0x01, 0x00, // Compression Code (Linear PCM)
					0x01, 0x00, // Number of channels (Monoral)
					0x44, 0xAC, 0x00, 0x00, // Sample rate (44.1Hz)
					0x44, 0xAC, 0x00, 0x00, // Average bytes per second (44.1Hz/Monoral)
					0x01, 0x00, // Block align (8bit/Monoral)
					0x08, 0x00, // Significant bits per sample (8bit)
				},
			},
			// sin wave
			riffbin.NewIncompleteSubChunk([4]byte{'d', 'a', 't', 'a'}, callbackReader(func() func(p []byte) (n int, err error) {
				max := 1000 * int(math.Ceil(44100/440))
				i := 0
				return func(p []byte) (n int, err error) {
					for n < len(p) && i < max {
						p[n] = byte(math.Floor((float64(i) / float64(max)) * 255.0 * (1.0 + math.Sin(2.0*math.Pi*float64(i)/(44100/440))) / 2.0))
						n++
						i++
					}
					if n == 0 {
						err = io.EOF
					}
					return
				}
			}())),
		},
	})
	if err != nil {
		panic(err)
	}

	// preview on macOS
	if os.Getenv("DEBUG_TEST_PLAY") != "" && runtime.GOOS == "darwin" {
		err = exec.Command("afplay", f.Name()).Run()
		if err != nil {
			panic(err)
		}
	}

	// Output:
}
