commit ceca244eaf56ed1eef23a0ca82ec77f8eed84d5f
Author: yangyudong <916291030@qq.com>
Date: Sat Apr 19 22:56:37 2025 +0800
init
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
new file mode 100755
index 0000000..88d0aea
--- /dev/null
+++ b/.github/workflows/go.yml
@@ -0,0 +1,51 @@
+# This workflow will build a golang project
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
+
+name: Go
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go-version: ['1.14', 'stable']
+ name: Build with Go ${{ matrix.go-version }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: ${{ matrix.go-version }}
+
+ - name: Install goveralls
+ if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }}
+ run: go install github.com/mattn/goveralls@latest
+
+ - name: Build
+ run: go build -v ./...
+
+ - name: Test
+ run: go test -v -covermode atomic -coverprofile=covprofile ./...
+
+ - name: Gofmt
+ # Run gofmt, print the output and exit with status code 1 if it isn't empty.
+ run: |
+ OUTPUT=$(gofmt -d ./)
+ echo "$OUTPUT"
+ test -z "$OUTPUT"
+
+ - name: Send coverage
+ if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }}
+ env:
+ COVERALLS_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
+ run: goveralls -coverprofile=covprofile -service=github
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..939f6a5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.flac
+*.wav
+_resources_
diff --git a/.gitmodules b/.gitmodules
new file mode 100755
index 0000000..aa52eb0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "flac-test-files"]
+ path = testdata/flac-test-files
+ url = https://github.com/ietf-wg-cellar/flac-test-files
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..68a49da
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..dc09430
--- /dev/null
+++ b/README.md
@@ -0,0 +1,80 @@
+# flac
+
+[](https://github.com/mewkiz/flac/actions/workflows/go.yml)
+[](https://coveralls.io/github/mewkiz/flac?branch=master)
+[](https://pkg.go.dev/github.com/mewkiz/flac)
+
+This package provides access to [FLAC][1] (Free Lossless Audio Codec) streams.
+
+[1]: http://flac.sourceforge.net/format.html
+
+## Documentation
+
+Documentation provided by GoDoc.
+
+- [flac]: provides access to FLAC (Free Lossless Audio Codec) streams.
+ - [frame][flac/frame]: implements access to FLAC audio frames.
+ - [meta][flac/meta]: implements access to FLAC metadata blocks.
+
+[flac]: http://pkg.go.dev/github.com/mewkiz/flac
+[flac/frame]: http://pkg.go.dev/github.com/mewkiz/flac/frame
+[flac/meta]: http://pkg.go.dev/github.com/mewkiz/flac/meta
+
+## Changes
+
+* Version 1.0.12 (2024-08-11)
+ - Improve performance of flac.NewSeek() by using a buffered reader (see [#72](https://github.com/mewkiz/flac/pull/72)).
+ - Fix off-by-one error in Seek end of stream check (see [#73](https://github.com/mewkiz/flac/pull/73)).
+
+* Version 1.0.11 (2024-08-04)
+ - Move example tools to dedicated [mewkiz/flac-tools](https://github.com/mewkiz/flac-tools) repository to reduce external dependencies (see [#62](https://github.com/mewkiz/flac/pull/62)).
+ - Fix seek to frame start (see [#71](https://github.com/mewkiz/flac/pull/71)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
+ - Simplify internal handling of io.Closer element in flac.Stream and flac.Encoder types (see [#70](https://github.com/mewkiz/flac/pull/70)). Thanks to [Mario Salgado](https://github.com/zalgonoise).
+
+* Version 1.0.10 (2023-11-11)
+ - Add support for LPC audio sample encoding (see [#66](https://github.com/mewkiz/flac/pull/66)). Thanks to [Mark Kremer](https://github.com/MarkKremer) for bug fixes and [Mattias Wadman](https://github.com/wader) for the invaluable [fq](https://github.com/wader/fq) tool used to investigate FLAC encoding issues.
+ - Replace Travis CI with GitHub actions for CI build status, test status and code coverage [#64](https://github.com/mewkiz/flac/pull/64)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
+
+* Version 1.0.9 (2023-10-24)
+ - Fix integer overflow during unfolding of rice residual (see [#61](https://github.com/mewkiz/flac/pull/61)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
+ - Fix decoding of escaped partition audio samples (see [#60](https://github.com/mewkiz/flac/issues/60)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
+ - Handle frame hashing of audio samples with bits-per-sample not evenly divisible by 8 (see [9d50c9e](https://github.com/mewkiz/flac/commit/9d50c9ee99ba322f487ed60442dc16f22b2affb8)).
+
+* Version 1.0.8 (2023-04-09)
+ - Fix race condition when reading meta data (see [#56](https://github.com/mewkiz/flac/pull/56)). Thanks to [Zach Orosz](https://github.com/zachorosz).
+ - Fix encoding of 8-bps WAV audio samples (see [#52](https://github.com/mewkiz/flac/pull/52)). Thanks to [Martijn van Beurden](https://github.com/ktmf01).
+ - Fix StreamInfo block type error message (see [#49](https://github.com/mewkiz/flac/pull/49)).
+
+* Version 1.0.7 (2021-01-28)
+ - Add seek API (see [#44](https://github.com/mewkiz/flac/pull/44) and [#46](https://github.com/mewkiz/flac/pull/46)). Thanks to [Craig Swank](https://github.com/cswank).
+
+* Version 1.0.6 (2019-12-20)
+ - Add experimental Encoder API to encode audio samples and metadata blocks (see [#32](https://github.com/mewkiz/flac/pull/32)).
+ - Use go.mod.
+ - Skip ID3v2 data prepended to flac files when parsing (see [36cc17e](https://github.com/mewkiz/flac/commit/36cc17efed51a9bae283d6a3a7a10997492945e7)).
+ - Remove dependency on encodebytes. Thanks to [Mikey Dickerson](https://github.com/mdickers47).
+ - Add 16kHz test case. Thanks to [Chewxy](https://github.com/chewxy).
+ - Fix lint issues (see [#25](https://github.com/mewkiz/flac/issues/25)).
+
+* Version 1.0.5 (2016-05-06)
+ - Simplify import paths. Drop use of gopkg.in, and rely on vendoring instead (see [azul3d/engine#1](https://github.com/azul3d/engine/issues/1)).
+ - Add FLAC decoding benchmark (see [d675e0a](https://github.com/mewkiz/flac/blob/d675e0aaccf2e43055f56b9b3feeddfdeed402e2/frame/frame_test.go#L60)).
+
+* Version 1.0.4 (2016-02-11)
+ - Add API examples to documentation (see [#11](https://github.com/mewkiz/flac/issues/11)).
+ - Extend test cases (see [aadf80a](https://github.com/mewkiz/flac/commit/aadf80aa28c463a94b8d5c49757e5a0948613ce2)).
+
+* Version 1.0.3 (2016-02-02)
+ - Implement decoding of FLAC files with wasted bits-per-sample (see [#12](https://github.com/mewkiz/flac/issues/12)).
+ - Stress test the library using [go-fuzz](https://github.com/dvyukov/go-fuzz) (see [#10](https://github.com/mewkiz/flac/pull/10)). Thanks to [Patrick Mézard](https://github.com/pmezard).
+
+* Version 1.0.2 (2015-06-05)
+ - Fix decoding of blocking strategy (see [#9](https://github.com/mewkiz/flac/pull/9)). Thanks to [Sergey Didyk](https://github.com/sdidyk).
+
+* Version 1.0.1 (2015-02-25)
+ - Fix two subframe decoding bugs (see [#7](https://github.com/mewkiz/flac/pull/7)). Thanks to [Jonathan MacMillan](https://github.com/perotinus).
+ - Add frame decoding test cases.
+
+* Version 1.0.0 (2014-09-30)
+ - Initial release.
+ - Implement decoding of FLAC files.
diff --git a/enc_test.go b/enc_test.go
new file mode 100755
index 0000000..de1acb6
--- /dev/null
+++ b/enc_test.go
@@ -0,0 +1,230 @@
+package flac_test
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "testing"
+
+ "github.com/mewkiz/flac"
+ "github.com/mewkiz/flac/meta"
+)
+
+func TestEncode(t *testing.T) {
+ paths := []string{
+ // metadata test cases.
+ "meta/testdata/input-SCPAP.flac",
+ "meta/testdata/input-SCVA.flac",
+ "meta/testdata/input-SCVPAP.flac",
+ "meta/testdata/input-VA.flac",
+ "meta/testdata/input-SCVAUP.flac", // empty metadata block (of type 0x7e)
+ "meta/testdata/input-SVAUP.flac", // empty metadata block (of type 0x7e)
+ "meta/testdata/silence.flac",
+ // flac test cases.
+ "testdata/19875.flac", // prediction method 3 (FIR)
+ "testdata/44127.flac", // prediction method 3 (FIR)
+ "testdata/59996.flac",
+ "testdata/80574.flac", // prediction method 3 (FIR)
+ "testdata/172960.flac",
+ "testdata/189983.flac",
+ "testdata/191885.flac",
+ "testdata/212768.flac",
+ "testdata/220014.flac", // prediction method 2 (Fixed)
+ "testdata/243749.flac", // prediction method 2 (Fixed)
+ "testdata/256529.flac",
+ "testdata/257344.flac", // prediction method 3 (FIR)
+ "testdata/8297-275156-0011.flac", // prediction method 3 (FIR)
+ "testdata/love.flac", // wasted bits
+ // IETF test cases.
+ "testdata/flac-test-files/subset/01 - blocksize 4096.flac",
+ "testdata/flac-test-files/subset/02 - blocksize 4608.flac",
+ "testdata/flac-test-files/subset/03 - blocksize 16.flac",
+ "testdata/flac-test-files/subset/04 - blocksize 192.flac",
+ "testdata/flac-test-files/subset/05 - blocksize 254.flac",
+ "testdata/flac-test-files/subset/06 - blocksize 512.flac",
+ "testdata/flac-test-files/subset/07 - blocksize 725.flac",
+ "testdata/flac-test-files/subset/08 - blocksize 1000.flac",
+ "testdata/flac-test-files/subset/09 - blocksize 1937.flac",
+ "testdata/flac-test-files/subset/10 - blocksize 2304.flac",
+ "testdata/flac-test-files/subset/11 - partition order 8.flac",
+ "testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac",
+ "testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac",
+ "testdata/flac-test-files/subset/14 - wasted bits.flac",
+ "testdata/flac-test-files/subset/15 - only verbatim subframes.flac",
+ "testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
+ "testdata/flac-test-files/subset/17 - all fixed orders.flac",
+ "testdata/flac-test-files/subset/18 - precision search.flac",
+ "testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac",
+ "testdata/flac-test-files/subset/20 - samplerate 39kHz.flac",
+ "testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac",
+ "testdata/flac-test-files/subset/22 - 12 bit per sample.flac",
+ "testdata/flac-test-files/subset/23 - 8 bit per sample.flac",
+ "testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac",
+ "testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac",
+ // NOTE: the only diff is that "26 - ...flac" uses `block_size: 0b111
+ // (end of header (16 bit))` to encode the block size at the end of the
+ // header, whereas mewkiz/flac encodes it directly `block_size: 4096
+ // (0b1100)`. Notably, the computed md5 hash of the decoded audio samples
+ // is identical (MD5: 3b2939b39ae7369b80451c77865e60c1). Thus, ignore the
+ // test case.
+ //"testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac",
+ // NOTE: the only diff is that "27 - ...flac" uses `block_size: 0b111
+ // (end of header (16 bit))` to encode the block size at the end of the
+ // header, whereas mewkiz/flac encodes it directly `block_size: 4608
+ // (0b101)`. Notably, the computed md5 hash of the decoded audio samples
+ // is identical (MD5: 9fb66177d2f735d4b1f501a5af1320a3). Thus, ignore the
+ // test case.
+ //"testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac",
+ "testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac",
+ "testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac",
+ "testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac",
+ "testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
+ "testdata/flac-test-files/subset/33 - samplerate 192kHz.flac",
+ // NOTE: the only diff is that "34 - ...flac" uses `0b1100 (end of header
+ // (8 bit*1000))` to encode the sample rate at the end of the header,
+ // whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the
+ // computed md5 hash of the decoded audio samples is identical
+ // (MD5: 942f56e503437dfd4c269c331774b2e3). Thus, ignore the test case.
+ //"testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac",
+ "testdata/flac-test-files/subset/36 - samplerate 384kHz.flac",
+ "testdata/flac-test-files/subset/37 - 20 bit per sample.flac",
+ "testdata/flac-test-files/subset/38 - 3 channels (3.0).flac",
+ "testdata/flac-test-files/subset/39 - 4 channels (4.0).flac",
+ "testdata/flac-test-files/subset/40 - 5 channels (5.0).flac",
+ "testdata/flac-test-files/subset/41 - 6 channels (5.1).flac",
+ "testdata/flac-test-files/subset/42 - 7 channels (6.1).flac",
+ "testdata/flac-test-files/subset/43 - 8 channels (7.1).flac",
+ // NOTE: the only diff is that "44 - ...flac" uses `0b1100 (end of header
+ // (8 bit*1000))` to encode the sample rate at the end of the header,
+ // whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the
+ // computed md5 hash of the decoded audio samples is identical
+ // (MD5: cdf531d4d4b95233986bc499518a89db). Thus, ignore the test case.
+ //"testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/45 - no total number of samples set.flac",
+ "testdata/flac-test-files/subset/46 - no min-max framesize set.flac",
+ "testdata/flac-test-files/subset/47 - only STREAMINFO.flac",
+ "testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac",
+ "testdata/flac-test-files/subset/49 - Extremely large PADDING.flac",
+ "testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac",
+ "testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac",
+ "testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac",
+ "testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac",
+ "testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac",
+ "testdata/flac-test-files/subset/55 - file 48-53 combined.flac",
+ "testdata/flac-test-files/subset/56 - JPG PICTURE.flac",
+ "testdata/flac-test-files/subset/57 - PNG PICTURE.flac",
+ "testdata/flac-test-files/subset/58 - GIF PICTURE.flac",
+ "testdata/flac-test-files/subset/59 - AVIF PICTURE.flac",
+ "testdata/flac-test-files/subset/60 - mono audio.flac",
+ "testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac",
+ "testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac",
+ "testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac",
+ "testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
+ }
+ for _, path := range paths {
+ t.Run(path, func(t *testing.T) {
+ // Decode source file.
+ stream, err := flac.ParseFile(path)
+ if err != nil {
+ t.Fatalf("%q: unable to parse FLAC file; %v", path, err)
+ }
+ defer stream.Close()
+
+ // Open encoder for FLAC stream.
+ out := new(bytes.Buffer)
+ enc, err := flac.NewEncoder(out, stream.Info, stream.Blocks...)
+ if err != nil {
+ t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err)
+ }
+ // Encode audio samples.
+ for {
+ frame, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err)
+ }
+ if err := enc.WriteFrame(frame); err != nil {
+ t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err)
+ }
+ }
+ // Close encoder and flush pending writes.
+ if err := enc.Close(); err != nil {
+ t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err)
+ }
+
+ // Compare source and destination FLAC streams.
+ want, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatalf("%q: unable to read file; %v", path, err)
+ }
+ got := out.Bytes()
+ if !bytes.Equal(got, want) {
+ t.Fatalf("%q: content mismatch; expected % X, got % X", path, want, got)
+ }
+ })
+ }
+}
+
+func TestEncodeComment(t *testing.T) {
+ // Decode FLAC file.
+ const path = "meta/testdata/input-VA.flac"
+ src, err := flac.ParseFile(path)
+ if err != nil {
+ t.Fatalf("unable to parse input FLAC file; %v", err)
+ }
+ defer src.Close()
+
+ // Add custom vorbis comment.
+ const want = "FLAC encoding test case"
+ for _, block := range src.Blocks {
+ if comment, ok := block.Body.(*meta.VorbisComment); ok {
+ comment.Vendor = want
+ }
+ }
+
+ // Open encoder for FLAC stream.
+ out := new(bytes.Buffer)
+ enc, err := flac.NewEncoder(out, src.Info, src.Blocks...)
+ if err != nil {
+ t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err)
+ }
+ // Encode audio samples.
+ for {
+ frame, err := src.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err)
+ }
+ if err := enc.WriteFrame(frame); err != nil {
+ t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err)
+ }
+ }
+ // Close encoder and flush pending writes.
+ if err := enc.Close(); err != nil {
+ t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err)
+ }
+
+ // Parse encoded FLAC file.
+ stream, err := flac.Parse(out)
+ if err != nil {
+ t.Fatalf("unable to parse output FLAC file; %v", err)
+ }
+ defer stream.Close()
+
+ // Add custom vorbis comment.
+ for _, block := range stream.Blocks {
+ if comment, ok := block.Body.(*meta.VorbisComment); ok {
+ got := comment.Vendor
+ if got != want {
+ t.Errorf("Vorbis comment mismatch; expected %q, got %q", want, got)
+ continue
+ }
+ }
+ }
+}
diff --git a/encode.go b/encode.go
new file mode 100755
index 0000000..892d7a7
--- /dev/null
+++ b/encode.go
@@ -0,0 +1,105 @@
+package flac
+
+import (
+ "crypto/md5"
+ "hash"
+ "io"
+
+ "github.com/icza/bitio"
+ "github.com/mewkiz/flac/meta"
+ "github.com/mewkiz/pkg/errutil"
+)
+
+// An Encoder represents a FLAC encoder.
+type Encoder struct {
+ // FLAC stream of encoder.
+ *Stream
+ // Underlying io.Writer or io.WriteCloser to the output stream.
+ w io.Writer
+ // Minimum and maximum block size (in samples) of frames written by encoder.
+ blockSizeMin, blockSizeMax uint16
+ // Minimum and maximum frame size (in bytes) of frames written by encoder.
+ frameSizeMin, frameSizeMax uint32
+ // MD5 running hash of unencoded audio samples.
+ md5sum hash.Hash
+ // Total number of samples (per channel) written by encoder.
+ nsamples uint64
+ // Current frame number if block size is fixed, and the first sample number
+ // of the current frame otherwise.
+ curNum uint64
+}
+
+// NewEncoder returns a new FLAC encoder for the given metadata StreamInfo block
+// and optional metadata blocks.
+func NewEncoder(w io.Writer, info *meta.StreamInfo, blocks ...*meta.Block) (*Encoder, error) {
+ // Store FLAC signature.
+ enc := &Encoder{
+ Stream: &Stream{
+ Info: info,
+ Blocks: blocks,
+ },
+ w: w,
+ md5sum: md5.New(),
+ }
+
+ bw := bitio.NewWriter(w)
+ if _, err := bw.Write(flacSignature); err != nil {
+ return nil, errutil.Err(err)
+ }
+ // Encode metadata blocks.
+ // TODO: consider using bufio.NewWriter.
+ if err := encodeStreamInfo(bw, info, len(blocks) == 0); err != nil {
+ return nil, errutil.Err(err)
+ }
+ for i, block := range blocks {
+ if err := encodeBlock(bw, block, i == len(blocks)-1); err != nil {
+ return nil, errutil.Err(err)
+ }
+ }
+ // Flush pending writes of metadata blocks.
+ if _, err := bw.Align(); err != nil {
+ return nil, errutil.Err(err)
+ }
+ // Return encoder to be used for encoding audio samples.
+ return enc, nil
+}
+
+// Close closes the underlying io.Writer of the encoder and flushes any pending
+// writes. If the io.Writer implements io.Seeker, the encoder will update the
+// StreamInfo metadata block with the MD5 checksum of the unencoded audio
+// samples, the number of samples, and the minimum and maximum frame size and
+// block size.
+func (enc *Encoder) Close() error {
+ // TODO: check if bit writer should be flushed before seeking on enc.w.
+ // Update StreamInfo metadata block.
+ if ws, ok := enc.w.(io.WriteSeeker); ok {
+ if _, err := ws.Seek(int64(len(flacSignature)), io.SeekStart); err != nil {
+ return errutil.Err(err)
+ }
+ // Update minimum and maximum block size (in samples) of FLAC stream.
+ enc.Info.BlockSizeMin = enc.blockSizeMin
+ enc.Info.BlockSizeMax = enc.blockSizeMax
+ // Update minimum and maximum frame size (in bytes) of FLAC stream.
+ enc.Info.FrameSizeMin = enc.frameSizeMin
+ enc.Info.FrameSizeMax = enc.frameSizeMax
+ // Update total number of samples (per channel) of FLAC stream.
+ enc.Info.NSamples = enc.nsamples
+ // Update MD5 checksum of the unencoded audio samples.
+ sum := enc.md5sum.Sum(nil)
+ for i := range sum {
+ enc.Info.MD5sum[i] = sum[i]
+ }
+ bw := bitio.NewWriter(ws)
+ // Write updated StreamInfo metadata block to output stream.
+ if err := encodeStreamInfo(bw, enc.Info, len(enc.Blocks) == 0); err != nil {
+ return errutil.Err(err)
+ }
+ if _, err := bw.Align(); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ if closer, ok := enc.w.(io.Closer); ok {
+ return closer.Close()
+ }
+ return nil
+}
diff --git a/encode_frame.go b/encode_frame.go
new file mode 100755
index 0000000..8822af1
--- /dev/null
+++ b/encode_frame.go
@@ -0,0 +1,427 @@
+package flac
+
+import (
+ "encoding/binary"
+ "io"
+ "math"
+
+ "github.com/icza/bitio"
+ "github.com/mewkiz/flac/frame"
+ "github.com/mewkiz/flac/internal/hashutil/crc16"
+ "github.com/mewkiz/flac/internal/hashutil/crc8"
+ "github.com/mewkiz/flac/internal/utf8"
+ "github.com/mewkiz/pkg/errutil"
+)
+
+// --- [ Frame ] ---------------------------------------------------------------
+
+// WriteFrame encodes the given audio frame to the output stream. The Num field
+// of the frame header is automatically calculated by the encoder.
+func (enc *Encoder) WriteFrame(f *frame.Frame) error {
+ // Sanity checks.
+ nchannels := int(enc.Info.NChannels)
+ if nchannels != len(f.Subframes) {
+ return errutil.Newf("subframe and channel count mismatch; expected %d, got %d", nchannels, len(f.Subframes))
+ }
+ nsamplesPerChannel := f.Subframes[0].NSamples
+ for i, subframe := range f.Subframes {
+ if nsamplesPerChannel != len(subframe.Samples) {
+ return errutil.Newf("invalid number of samples in channel %d; expected %d, got %d", i, nsamplesPerChannel, len(subframe.Samples))
+ }
+ }
+ if nchannels != f.Channels.Count() {
+ return errutil.Newf("channel count mismatch; expected %d, got %d", nchannels, f.Channels.Count())
+ }
+
+ // Create a new CRC-16 hash writer which adds the data from all write
+ // operations to a running hash.
+ h := crc16.NewIBM()
+ hw := io.MultiWriter(h, enc.w)
+
+ // Encode frame header.
+ f.Num = enc.curNum
+ if f.HasFixedBlockSize {
+ enc.curNum++
+ } else {
+ enc.curNum += uint64(nsamplesPerChannel)
+ }
+ enc.nsamples += uint64(nsamplesPerChannel)
+ blockSize := uint16(nsamplesPerChannel)
+ if enc.blockSizeMin == 0 || blockSize < enc.blockSizeMin {
+ enc.blockSizeMin = blockSize
+ }
+ if enc.blockSizeMax == 0 || blockSize > enc.blockSizeMax {
+ enc.blockSizeMax = blockSize
+ }
+ // TODO: track number of bytes written to hw, to update values of
+ // frameSizeMin and frameSizeMax.
+ // Add unencoded audio samples to running MD5 hash.
+ f.Hash(enc.md5sum)
+ if err := enc.encodeFrameHeader(hw, f.Header); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Inter-channel decorrelation of subframe samples.
+ f.Decorrelate()
+ defer f.Correlate() // NOTE: revert decorrelation of audio samples after encoding is done (to make encode non-destructive).
+
+ // Encode subframes.
+ bw := bitio.NewWriter(hw)
+ for channel, subframe := range f.Subframes {
+ // The side channel requires an extra bit per sample when using
+ // inter-channel decorrelation.
+ bps := uint(f.BitsPerSample)
+ switch f.Channels {
+ case frame.ChannelsSideRight:
+ // channel 0 is the side channel.
+ if channel == 0 {
+ bps++
+ }
+ case frame.ChannelsLeftSide, frame.ChannelsMidSide:
+ // channel 1 is the side channel.
+ if channel == 1 {
+ bps++
+ }
+ }
+
+ if err := encodeSubframe(bw, f.Header, subframe, bps); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // Zero-padding to byte alignment.
+ // Flush pending writes to subframe.
+ if _, err := bw.Align(); err != nil {
+ return errutil.Err(err)
+ }
+
+ // CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of
+ // everything before the crc, back to and including the frame header sync
+ // code.
+ crc := h.Sum16()
+ if err := binary.Write(enc.w, binary.BigEndian, crc); err != nil {
+ return errutil.Err(err)
+ }
+
+ return nil
+}
+
+// --- [ Frame header ] --------------------------------------------------------
+
+// encodeFrameHeader encodes the given frame header, writing to w.
+func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error {
+ // Create a new CRC-8 hash writer which adds the data from all write
+ // operations to a running hash.
+ h := crc8.NewATM()
+ hw := io.MultiWriter(h, w)
+ bw := bitio.NewWriter(hw)
+
+ // Closing the *bitio.Writer will not close the underlying writer
+ defer bw.Close()
+
+ // Sync code: 11111111111110
+ if err := bw.WriteBits(0x3FFE, 14); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Reserved: 0
+ if err := bw.WriteBits(0x0, 1); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Blocking strategy:
+ // 0 : fixed-blocksize stream; frame header encodes the frame number
+ // 1 : variable-blocksize stream; frame header encodes the sample number
+ if err := bw.WriteBool(!hdr.HasFixedBlockSize); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode block size.
+ nblockSizeSuffixBits, err := encodeFrameHeaderBlockSize(bw, hdr.BlockSize)
+ if err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode sample rate.
+ sampleRateSuffixBits, nsampleRateSuffixBits, err := encodeFrameHeaderSampleRate(bw, hdr.SampleRate)
+ if err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode channels assignment.
+ if err := encodeFrameHeaderChannels(bw, hdr.Channels); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode bits-per-sample.
+ if err := encodeFrameHeaderBitsPerSample(bw, hdr.BitsPerSample); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Reserved: 0
+ if err := bw.WriteBits(0x0, 1); err != nil {
+ return errutil.Err(err)
+ }
+
+ // if (variable blocksize)
+ // <8-56>:"UTF-8" coded sample number (decoded number is 36 bits)
+ // else
+ // <8-48>:"UTF-8" coded frame number (decoded number is 31 bits)
+ if err := utf8.Encode(bw, hdr.Num); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Write block size after the frame header (used for uncommon block sizes).
+ if nblockSizeSuffixBits > 0 {
+ // 0110 : get 8 bit (blocksize-1) from end of header
+ // 0111 : get 16 bit (blocksize-1) from end of header
+ if err := bw.WriteBits(uint64(hdr.BlockSize-1), nblockSizeSuffixBits); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // Write sample rate after the frame header (used for uncommon sample rates).
+ if nsampleRateSuffixBits > 0 {
+ if err := bw.WriteBits(sampleRateSuffixBits, nsampleRateSuffixBits); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // Flush pending writes to frame header.
+ if _, err := bw.Align(); err != nil {
+ return errutil.Err(err)
+ }
+
+ // CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) of
+ // everything before the crc, including the sync code.
+ crc := h.Sum8()
+ if err := binary.Write(w, binary.BigEndian, crc); err != nil {
+ return errutil.Err(err)
+ }
+
+ return nil
+}
+
+// ~~~ [ Block size ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// encodeFrameHeaderBlockSize encodes the block size of the frame header,
+// writing to bw. It returns the number of bits used to store block size after
+// the frame header.
+func encodeFrameHeaderBlockSize(bw *bitio.Writer, blockSize uint16) (nblockSizeSuffixBits byte, err error) {
+ // Block size in inter-channel samples:
+ // 0000 : reserved
+ // 0001 : 192 samples
+ // 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
+ // 0110 : get 8 bit (blocksize-1) from end of header
+ // 0111 : get 16 bit (blocksize-1) from end of header
+ // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
+ var bits uint64
+ switch blockSize {
+ case 192:
+ // 0001
+ bits = 0x1
+ case 576, 1152, 2304, 4608:
+ // 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
+ bits = 0x2 + uint64(math.Log2(float64(blockSize/576)))
+ case 256, 512, 1024, 2048, 4096, 8192, 16384, 32768:
+ // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
+ bits = 0x8 + uint64(math.Log2(float64(blockSize/256)))
+ default:
+ if blockSize <= 256 {
+ // 0110 : get 8 bit (blocksize-1) from end of header
+ bits = 0x6
+ nblockSizeSuffixBits = 8
+ } else {
+ // 0111 : get 16 bit (blocksize-1) from end of header
+ bits = 0x7
+ nblockSizeSuffixBits = 16
+ }
+ }
+ if err := bw.WriteBits(bits, 4); err != nil {
+ return 0, errutil.Err(err)
+ }
+ return nblockSizeSuffixBits, nil
+}
+
+// ~~~ [ Sample rate ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// encodeFrameHeaderSampleRate encodes the sample rate of the frame header,
+// writing to bw. It returns the bits and the number of bits used to store
+// sample rate after the frame header.
+func encodeFrameHeaderSampleRate(bw *bitio.Writer, sampleRate uint32) (sampleRateSuffixBits uint64, nsampleRateSuffixBits byte, err error) {
+ // Sample rate:
+ // 0000 : get from STREAMINFO metadata block
+ // 0001 : 88.2kHz
+ // 0010 : 176.4kHz
+ // 0011 : 192kHz
+ // 0100 : 8kHz
+ // 0101 : 16kHz
+ // 0110 : 22.05kHz
+ // 0111 : 24kHz
+ // 1000 : 32kHz
+ // 1001 : 44.1kHz
+ // 1010 : 48kHz
+ // 1011 : 96kHz
+ // 1100 : get 8 bit sample rate (in kHz) from end of header
+ // 1101 : get 16 bit sample rate (in Hz) from end of header
+ // 1110 : get 16 bit sample rate (in tens of Hz) from end of header
+ // 1111 : invalid, to prevent sync-fooling string of 1s
+ var bits uint64
+ switch sampleRate {
+ case 0:
+ // 0000 : get from STREAMINFO metadata block
+ bits = 0
+ case 88200:
+ // 0001 : 88.2kHz
+ bits = 0x1
+ case 176400:
+ // 0010 : 176.4kHz
+ bits = 0x2
+ case 192000:
+ // 0011 : 192kHz
+ bits = 0x3
+ case 8000:
+ // 0100 : 8kHz
+ bits = 0x4
+ case 16000:
+ // 0101 : 16kHz
+ bits = 0x5
+ case 22050:
+ // 0110 : 22.05kHz
+ bits = 0x6
+ case 24000:
+ // 0111 : 24kHz
+ bits = 0x7
+ case 32000:
+ // 1000 : 32kHz
+ bits = 0x8
+ case 44100:
+ // 1001 : 44.1kHz
+ bits = 0x9
+ case 48000:
+ // 1010 : 48kHz
+ bits = 0xA
+ case 96000:
+ // 1011 : 96kHz
+ bits = 0xB
+ default:
+ switch {
+ case sampleRate <= 255000 && sampleRate%1000 == 0:
+ // 1100 : get 8 bit sample rate (in kHz) from end of header
+ bits = 0xC
+ sampleRateSuffixBits = uint64(sampleRate / 1000)
+ nsampleRateSuffixBits = 8
+ case sampleRate <= 65535:
+ // 1101 : get 16 bit sample rate (in Hz) from end of header
+ bits = 0xD
+ sampleRateSuffixBits = uint64(sampleRate)
+ nsampleRateSuffixBits = 16
+ case sampleRate <= 655350 && sampleRate%10 == 0:
+ // 1110 : get 16 bit sample rate (in tens of Hz) from end of header
+ bits = 0xE
+ sampleRateSuffixBits = uint64(sampleRate / 10)
+ nsampleRateSuffixBits = 16
+ default:
+ return 0, 0, errutil.Newf("unable to encode sample rate %v", sampleRate)
+ }
+ }
+ if err := bw.WriteBits(bits, 4); err != nil {
+ return 0, 0, errutil.Err(err)
+ }
+ return sampleRateSuffixBits, nsampleRateSuffixBits, nil
+}
+
+// ~~~ [ Channels assignment ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// encodeFrameHeaderChannels encodes the channels assignment of the frame
+// header, writing to bw.
+func encodeFrameHeaderChannels(bw *bitio.Writer, channels frame.Channels) error {
+ // Channel assignment.
+ // 0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations. The assignments are as follows:
+ // 1 channel: mono
+ // 2 channels: left, right
+ // 3 channels: left, right, center
+ // 4 channels: front left, front right, back left, back right
+ // 5 channels: front left, front right, front center, back/surround left, back/surround right
+ // 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
+ // 7 channels: front left, front right, front center, LFE, back center, side left, side right
+ // 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
+ // 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
+ // 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
+ // 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
+ // 1011-1111 : reserved
+ var bits uint64
+ switch channels {
+ case frame.ChannelsMono, frame.ChannelsLR, frame.ChannelsLRC, frame.ChannelsLRLsRs, frame.ChannelsLRCLsRs, frame.ChannelsLRCLfeLsRs, frame.ChannelsLRCLfeCsSlSr, frame.ChannelsLRCLfeLsRsSlSr:
+ // 1 channel: mono.
+ // 2 channels: left, right.
+ // 3 channels: left, right, center.
+ // 4 channels: left, right, left surround, right surround.
+ // 5 channels: left, right, center, left surround, right surround.
+ // 6 channels: left, right, center, LFE, left surround, right surround.
+ // 7 channels: left, right, center, LFE, center surround, side left, side right.
+ // 8 channels: left, right, center, LFE, left surround, right surround, side left, side right.
+ bits = uint64(channels.Count() - 1)
+ case frame.ChannelsLeftSide:
+ // 2 channels: left, side; using inter-channel decorrelation.
+ // 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
+ bits = 0x8
+ case frame.ChannelsSideRight:
+ // 2 channels: side, right; using inter-channel decorrelation.
+ // 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
+ bits = 0x9
+ case frame.ChannelsMidSide:
+ // 2 channels: mid, side; using inter-channel decorrelation.
+ // 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
+ bits = 0xA
+ default:
+ return errutil.Newf("support for channel assignment %v not yet implemented", channels)
+ }
+ if err := bw.WriteBits(bits, 4); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// ~~~ [ Bits-per-sample ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// encodeFrameHeaderBitsPerSample encodes the bits-per-sample of the frame
+// header, writing to bw.
+func encodeFrameHeaderBitsPerSample(bw *bitio.Writer, bps uint8) error {
+ // Sample size in bits:
+ // 000 : get from STREAMINFO metadata block
+ // 001 : 8 bits per sample
+ // 010 : 12 bits per sample
+ // 011 : reserved
+ // 100 : 16 bits per sample
+ // 101 : 20 bits per sample
+ // 110 : 24 bits per sample
+ // 111 : reserved
+ var bits uint64
+ switch bps {
+ case 0:
+ // 000 : get from STREAMINFO metadata block
+ bits = 0x0
+ case 8:
+ // 001 : 8 bits per sample
+ bits = 0x1
+ case 12:
+ // 010 : 12 bits per sample
+ bits = 0x2
+ case 16:
+ // 100 : 16 bits per sample
+ bits = 0x4
+ case 20:
+ // 101 : 20 bits per sample
+ bits = 0x5
+ case 24:
+ // 110 : 24 bits per sample
+ bits = 0x6
+ default:
+ return errutil.Newf("support for sample size %v not yet implemented", bps)
+ }
+ if err := bw.WriteBits(bits, 3); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
diff --git a/encode_meta.go b/encode_meta.go
new file mode 100755
index 0000000..2a7edfe
--- /dev/null
+++ b/encode_meta.go
@@ -0,0 +1,419 @@
+package flac
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+
+ "github.com/icza/bitio"
+ "github.com/mewkiz/flac/internal/ioutilx"
+ "github.com/mewkiz/flac/meta"
+ "github.com/mewkiz/pkg/errutil"
+)
+
+// --- [ Metadata block ] ------------------------------------------------------
+
+// encodeBlock encodes the metadata block, writing to bw.
+func encodeBlock(bw *bitio.Writer, block *meta.Block, last bool) error {
+ if block.Type == meta.TypePadding {
+ return encodePadding(bw, block.Length, last)
+ }
+ if block.Length == 0 {
+ return encodeEmptyBlock(bw, block.Type, last)
+ }
+ switch body := block.Body.(type) {
+ case *meta.StreamInfo:
+ return encodeStreamInfo(bw, body, last)
+ case *meta.Application:
+ return encodeApplication(bw, body, last)
+ case *meta.SeekTable:
+ return encodeSeekTable(bw, body, last)
+ case *meta.VorbisComment:
+ return encodeVorbisComment(bw, body, last)
+ case *meta.CueSheet:
+ return encodeCueSheet(bw, body, last)
+ case *meta.Picture:
+ return encodePicture(bw, body, last)
+ default:
+ panic(fmt.Errorf("support for metadata block body type %T not yet implemented", body))
+ }
+}
+
+// --- [ Metadata block header ] -----------------------------------------------
+
+// encodeEmptyBlock encodes the metadata block header of an empty metadata
+// block with the specified type, writing to bw.
+func encodeEmptyBlock(bw *bitio.Writer, typ meta.Type, last bool) error {
+ // Store metadata block header.
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: typ,
+ Length: 0,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ Metadata block header ] -----------------------------------------------
+
+// encodeBlockHeader encodes the metadata block header, writing to bw.
+func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error {
+ // 1 bit: IsLast.
+ if err := bw.WriteBool(hdr.IsLast); err != nil {
+ return errutil.Err(err)
+ }
+ // 7 bits: Type.
+ if err := bw.WriteBits(uint64(hdr.Type), 7); err != nil {
+ return errutil.Err(err)
+ }
+ // 24 bits: Length.
+ if err := bw.WriteBits(uint64(hdr.Length), 24); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ StreamInfo ] ----------------------------------------------------------
+
+// encodeStreamInfo encodes the StreamInfo metadata block, writing to bw.
+func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool) error {
+ // Store metadata block header.
+ const nbits = 16 + 16 + 24 + 24 + 20 + 3 + 5 + 36 + 8*16
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypeStreamInfo,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ // 16 bits: BlockSizeMin.
+ if err := bw.WriteBits(uint64(info.BlockSizeMin), 16); err != nil {
+ return errutil.Err(err)
+ }
+ // 16 bits: BlockSizeMax.
+ if err := bw.WriteBits(uint64(info.BlockSizeMax), 16); err != nil {
+ return errutil.Err(err)
+ }
+ // 24 bits: FrameSizeMin.
+ if err := bw.WriteBits(uint64(info.FrameSizeMin), 24); err != nil {
+ return errutil.Err(err)
+ }
+ // 24 bits: FrameSizeMax.
+ if err := bw.WriteBits(uint64(info.FrameSizeMax), 24); err != nil {
+ return errutil.Err(err)
+ }
+ // 20 bits: SampleRate.
+ if err := bw.WriteBits(uint64(info.SampleRate), 20); err != nil {
+ return errutil.Err(err)
+ }
+ // 3 bits: NChannels; stored as (number of channels) - 1.
+ if err := bw.WriteBits(uint64(info.NChannels-1), 3); err != nil {
+ return errutil.Err(err)
+ }
+ // 5 bits: BitsPerSample; stored as (bits-per-sample) - 1.
+ if err := bw.WriteBits(uint64(info.BitsPerSample-1), 5); err != nil {
+ return errutil.Err(err)
+ }
+ // 36 bits: NSamples.
+ if err := bw.WriteBits(info.NSamples, 36); err != nil {
+ return errutil.Err(err)
+ }
+ // 16 bytes: MD5sum.
+ if _, err := bw.Write(info.MD5sum[:]); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ Padding ] ----------------------------------------------------------
+
+// encodePadding encodes the Padding metadata block, writing to bw.
+func encodePadding(bw *bitio.Writer, length int64, last bool) error {
+ // Store metadata block header.
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypePadding,
+ Length: length,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+ // Store metadata block body.
+ if _, err := io.CopyN(bw, ioutilx.Zero, length); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ Application ] ---------------------------------------------------------
+
+// encodeApplication encodes the Application metadata block, writing to bw.
+func encodeApplication(bw *bitio.Writer, app *meta.Application, last bool) error {
+ // Store metadata block header.
+ nbits := int64(32 + 8*len(app.Data))
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypeApplication,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ // 32 bits: ID.
+ if err := bw.WriteBits(uint64(app.ID), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // TODO: check if the Application block may contain only an ID.
+ if _, err := bw.Write(app.Data); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ SeekTable ] -----------------------------------------------------------
+
+// encodeSeekTable encodes the SeekTable metadata block, writing to bw.
+func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool) error {
+ // Store metadata block header.
+ nbits := int64((64 + 64 + 16) * len(table.Points))
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypeSeekTable,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ for _, point := range table.Points {
+ if err := binary.Write(bw, binary.BigEndian, point); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ return nil
+}
+
+// --- [ VorbisComment ] -------------------------------------------------------
+
+// encodeVorbisComment encodes the VorbisComment metadata block, writing to bw.
+func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, last bool) error {
+ // Store metadata block header.
+ nbits := int64(32 + 8*len(comment.Vendor) + 32)
+ for _, tag := range comment.Tags {
+ nbits += int64(32 + 8*(len(tag[0])+1+len(tag[1])))
+ }
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypeVorbisComment,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ // 32 bits: vendor length.
+ // TODO: verify that little-endian encoding is used; otherwise, switch to
+ // using bw.WriteBits.
+ if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Vendor))); err != nil {
+ return errutil.Err(err)
+ }
+ // (vendor length) bits: Vendor.
+ if _, err := bw.Write([]byte(comment.Vendor)); err != nil {
+ return errutil.Err(err)
+ }
+ // Store tags.
+ // 32 bits: number of tags.
+ if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Tags))); err != nil {
+ return errutil.Err(err)
+ }
+ for _, tag := range comment.Tags {
+ // Store tag, which has the following format:
+ // NAME=VALUE
+ buf := []byte(fmt.Sprintf("%s=%s", tag[0], tag[1]))
+ // 32 bits: vector length
+ if err := binary.Write(bw, binary.LittleEndian, uint32(len(buf))); err != nil {
+ return errutil.Err(err)
+ }
+ // (vector length): vector.
+ if _, err := bw.Write(buf); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ return nil
+}
+
+// --- [ CueSheet ] ------------------------------------------------------------
+
+// encodeCueSheet encodes the CueSheet metadata block, writing to bw.
+func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error {
+ // Store metadata block header.
+ nbits := int64(8*128 + 64 + 1 + 7 + 8*258 + 8)
+ for _, track := range cs.Tracks {
+ nbits += 64 + 8 + 8*12 + 1 + 1 + 6 + 8*13 + 8
+ for range track.Indicies {
+ nbits += 64 + 8 + 8*3
+ }
+ }
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypeCueSheet,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ // Store cue sheet.
+ // 128 bytes: MCN.
+ var mcn [128]byte
+ copy(mcn[:], cs.MCN)
+ if _, err := bw.Write(mcn[:]); err != nil {
+ return errutil.Err(err)
+ }
+ // 64 bits: NLeadInSamples.
+ if err := bw.WriteBits(cs.NLeadInSamples, 64); err != nil {
+ return errutil.Err(err)
+ }
+ // 1 bit: IsCompactDisc.
+ if err := bw.WriteBool(cs.IsCompactDisc); err != nil {
+ return errutil.Err(err)
+ }
+ // 7 bits and 258 bytes: reserved.
+ if err := bw.WriteBits(0, 7); err != nil {
+ return errutil.Err(err)
+ }
+ if _, err := io.CopyN(bw, ioutilx.Zero, 258); err != nil {
+ return errutil.Err(err)
+ }
+ // Store cue sheet tracks.
+ // 8 bits: (number of tracks)
+ if err := bw.WriteBits(uint64(len(cs.Tracks)), 8); err != nil {
+ return errutil.Err(err)
+ }
+ for _, track := range cs.Tracks {
+ // 64 bits: Offset.
+ if err := bw.WriteBits(track.Offset, 64); err != nil {
+ return errutil.Err(err)
+ }
+ // 8 bits: Num.
+ if err := bw.WriteBits(uint64(track.Num), 8); err != nil {
+ return errutil.Err(err)
+ }
+ // 12 bytes: ISRC.
+ var isrc [12]byte
+ copy(isrc[:], track.ISRC)
+ if _, err := bw.Write(isrc[:]); err != nil {
+ return errutil.Err(err)
+ }
+ // 1 bit: IsAudio.
+ if err := bw.WriteBool(!track.IsAudio); err != nil {
+ return errutil.Err(err)
+ }
+ // 1 bit: HasPreEmphasis.
+ // mask = 01000000
+ if err := bw.WriteBool(track.HasPreEmphasis); err != nil {
+ return errutil.Err(err)
+ }
+ // 6 bits and 13 bytes: reserved.
+ // mask = 00111111
+ if err := bw.WriteBits(0, 6); err != nil {
+ return errutil.Err(err)
+ }
+ if _, err := io.CopyN(bw, ioutilx.Zero, 13); err != nil {
+ return errutil.Err(err)
+ }
+ // Store indicies.
+ // 8 bits: (number of indicies)
+ if err := bw.WriteBits(uint64(len(track.Indicies)), 8); err != nil {
+ return errutil.Err(err)
+ }
+ for _, index := range track.Indicies {
+ // 64 bits: Offset.
+ if err := bw.WriteBits(index.Offset, 64); err != nil {
+ return errutil.Err(err)
+ }
+ // 8 bits: Num.
+ if err := bw.WriteBits(uint64(index.Num), 8); err != nil {
+ return errutil.Err(err)
+ }
+ // 3 bytes: reserved.
+ if _, err := io.CopyN(bw, ioutilx.Zero, 3); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ }
+ return nil
+}
+
+// --- [ Picture ] -------------------------------------------------------------
+
+// encodePicture encodes the Picture metadata block, writing to bw.
+func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error {
+ // Store metadata block header.
+ nbits := int64(32 + 32 + 8*len(pic.MIME) + 32 + 8*len(pic.Desc) + 32 + 32 + 32 + 32 + 32 + 8*len(pic.Data))
+ hdr := &meta.Header{
+ IsLast: last,
+ Type: meta.TypePicture,
+ Length: nbits / 8,
+ }
+ if err := encodeBlockHeader(bw, hdr); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store metadata block body.
+ // 32 bits: Type.
+ if err := bw.WriteBits(uint64(pic.Type), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: (MIME type length).
+ if err := bw.WriteBits(uint64(len(pic.MIME)), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // (MIME type length) bytes: MIME.
+ if _, err := bw.Write([]byte(pic.MIME)); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: (description length).
+ if err := bw.WriteBits(uint64(len(pic.Desc)), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // (description length) bytes: Desc.
+ if _, err := bw.Write([]byte(pic.Desc)); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: Width.
+ if err := bw.WriteBits(uint64(pic.Width), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: Height.
+ if err := bw.WriteBits(uint64(pic.Height), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: Depth.
+ if err := bw.WriteBits(uint64(pic.Depth), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: NPalColors.
+ if err := bw.WriteBits(uint64(pic.NPalColors), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // 32 bits: (data length).
+ if err := bw.WriteBits(uint64(len(pic.Data)), 32); err != nil {
+ return errutil.Err(err)
+ }
+ // (data length) bytes: Data.
+ if _, err := bw.Write(pic.Data); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
diff --git a/encode_subframe.go b/encode_subframe.go
new file mode 100755
index 0000000..f74b0d4
--- /dev/null
+++ b/encode_subframe.go
@@ -0,0 +1,369 @@
+package flac
+
+import (
+ "fmt"
+
+ "github.com/icza/bitio"
+ "github.com/mewkiz/flac/frame"
+ iobits "github.com/mewkiz/flac/internal/bits"
+ "github.com/mewkiz/pkg/errutil"
+)
+
+// --- [ Subframe ] ------------------------------------------------------------
+
+// encodeSubframe encodes the given subframe, writing to bw.
+func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
+ // Encode subframe header.
+ if err := encodeSubframeHeader(bw, subframe.SubHeader); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Adjust bps of subframe for wasted bits-per-sample.
+ bps -= subframe.Wasted
+
+ // Right shift to account for wasted bits-per-sample.
+ if subframe.Wasted > 0 {
+ for i, sample := range subframe.Samples {
+ subframe.Samples[i] = sample >> subframe.Wasted
+ }
+ // NOTE: use defer to restore original samples after encode.
+ defer func() {
+ for i, sample := range subframe.Samples {
+ subframe.Samples[i] = sample << subframe.Wasted
+ }
+ }()
+ }
+
+ // Encode audio samples.
+ switch subframe.Pred {
+ case frame.PredConstant:
+ if err := encodeConstantSamples(bw, hdr, subframe, bps); err != nil {
+ return errutil.Err(err)
+ }
+ case frame.PredVerbatim:
+ if err := encodeVerbatimSamples(bw, hdr, subframe, bps); err != nil {
+ return errutil.Err(err)
+ }
+ case frame.PredFixed:
+ if err := encodeFixedSamples(bw, hdr, subframe, bps); err != nil {
+ return errutil.Err(err)
+ }
+ case frame.PredFIR:
+ if err := encodeFIRSamples(bw, hdr, subframe, bps); err != nil {
+ return errutil.Err(err)
+ }
+ default:
+ return errutil.Newf("support for prediction method %v not yet implemented", subframe.Pred)
+ }
+ return nil
+}
+
+// --- [ Subframe header ] -----------------------------------------------------
+
+// encodeSubframeHeader encodes the given subframe header, writing to bw.
+func encodeSubframeHeader(bw *bitio.Writer, subHdr frame.SubHeader) error {
+ // Zero bit padding, to prevent sync-fooling string of 1s.
+ if err := bw.WriteBits(0x0, 1); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Subframe type:
+ // 000000 : SUBFRAME_CONSTANT
+ // 000001 : SUBFRAME_VERBATIM
+ // 00001x : reserved
+ // 0001xx : reserved
+ // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
+ // 01xxxx : reserved
+ // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1
+ var bits uint64
+ switch subHdr.Pred {
+ case frame.PredConstant:
+ // 000000 : SUBFRAME_CONSTANT
+ bits = 0x00
+ case frame.PredVerbatim:
+ // 000001 : SUBFRAME_VERBATIM
+ bits = 0x01
+ case frame.PredFixed:
+ // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
+ bits = 0x08 | uint64(subHdr.Order)
+ case frame.PredFIR:
+ // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1
+ bits = 0x20 | uint64(subHdr.Order-1)
+ }
+ if err := bw.WriteBits(bits, 6); err != nil {
+ return errutil.Err(err)
+ }
+
+ // <1+k> 'Wasted bits-per-sample' flag:
+ //
+ // 0 : no wasted bits-per-sample in source subblock, k=0
+ // 1 : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 => 001 follows, k=7 => 0000001 follows.
+ hasWastedBits := subHdr.Wasted > 0
+ if err := bw.WriteBool(hasWastedBits); err != nil {
+ return errutil.Err(err)
+ }
+ if hasWastedBits {
+ if err := iobits.WriteUnary(bw, uint64(subHdr.Wasted-1)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ return nil
+}
+
+// --- [ Constant samples ] ----------------------------------------------------
+
+// encodeConstantSamples stores the given constant sample, writing to bw.
+func encodeConstantSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
+ samples := subframe.Samples
+ sample := samples[0]
+ for _, s := range samples[1:] {
+ if sample != s {
+ return errutil.Newf("constant sample mismatch; expected %v, got %v", sample, s)
+ }
+ }
+ // Unencoded constant value of the subblock, n = frame's bits-per-sample.
+ if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ Verbatim samples ] ----------------------------------------------------
+
+// encodeVerbatimSamples stores the given samples verbatim (uncompressed),
+// writing to bw.
+func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
+ // Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize.
+ samples := subframe.Samples
+ if int(hdr.BlockSize) != len(samples) {
+ return errutil.Newf("block size and sample count mismatch; expected %d, got %d", hdr.BlockSize, len(samples))
+ }
+ for _, sample := range samples {
+ if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ return nil
+}
+
+// --- [ Fixed samples ] -------------------------------------------------------
+
+// encodeFixedSamples stores the given samples using linear prediction coding
+// with a fixed set of predefined polynomial coefficients, writing to bw.
+func encodeFixedSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
+ // Encode unencoded warm-up samples.
+ samples := subframe.Samples
+ for i := 0; i < subframe.Order; i++ {
+ sample := samples[i]
+ if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // Compute residuals (signal errors of the prediction) between audio
+ // samples and LPC predicted audio samples.
+ const shift = 0
+ residuals, err := getLPCResiduals(subframe, frame.FixedCoeffs[subframe.Order], shift)
+ if err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode subframe residuals.
+ if err := encodeResiduals(bw, subframe, residuals); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// --- [ FIR samples ] -------------------------------------------------------
+
+// encodeFIRSamples stores the given samples using linear prediction coding
+// with a custom set of predefined polynomial coefficients, writing to bw.
+func encodeFIRSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
+ // Encode unencoded warm-up samples.
+ samples := subframe.Samples
+ for i := 0; i < subframe.Order; i++ {
+ sample := samples[i]
+ if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // 4 bits: (coefficients' precision in bits) - 1.
+ if err := bw.WriteBits(uint64(subframe.CoeffPrec-1), 4); err != nil {
+ return errutil.Err(err)
+ }
+
+ // 5 bits: predictor coefficient shift needed in bits.
+ if err := bw.WriteBits(uint64(subframe.CoeffShift), 5); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode coefficients.
+ for _, coeff := range subframe.Coeffs {
+ // (prec) bits: Predictor coefficient.
+ if err := bw.WriteBits(uint64(coeff), uint8(subframe.CoeffPrec)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+
+ // Compute residuals (signal errors of the prediction) between audio
+ // samples and LPC predicted audio samples.
+ residuals, err := getLPCResiduals(subframe, subframe.Coeffs, subframe.CoeffShift)
+ if err != nil {
+ return errutil.Err(err)
+ }
+
+ // Encode subframe residuals.
+ if err := encodeResiduals(bw, subframe, residuals); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// encodeResiduals encodes the residuals (prediction method error signals) of the
+// subframe.
+//
+// ref: https://www.xiph.org/flac/format.html#residual
+func encodeResiduals(bw *bitio.Writer, subframe *frame.Subframe, residuals []int32) error {
+ // 2 bits: Residual coding method.
+ if err := bw.WriteBits(uint64(subframe.ResidualCodingMethod), 2); err != nil {
+ return errutil.Err(err)
+ }
+ // The 2 bits are used to specify the residual coding method as follows:
+ // 00: Rice coding with a 4-bit Rice parameter.
+ // 01: Rice coding with a 5-bit Rice parameter.
+ // 10: reserved.
+ // 11: reserved.
+ switch subframe.ResidualCodingMethod {
+ case frame.ResidualCodingMethodRice1:
+ return encodeRicePart(bw, subframe, 4, residuals)
+ case frame.ResidualCodingMethodRice2:
+ return encodeRicePart(bw, subframe, 5, residuals)
+ default:
+ return fmt.Errorf("encodeResiduals: reserved residual coding method bit pattern (%02b)", uint8(subframe.ResidualCodingMethod))
+ }
+}
+
+// encodeRicePart encodes a Rice partition of residuals from the subframe, using
+// a Rice parameter of the specified size in bits.
+//
+// ref: https://www.xiph.org/flac/format.html#partitioned_rice
+// ref: https://www.xiph.org/flac/format.html#partitioned_rice2
+func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSize uint, residuals []int32) error {
+ // 4 bits: Partition order.
+ riceSubframe := subframe.RiceSubframe
+ if err := bw.WriteBits(uint64(riceSubframe.PartOrder), 4); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Parse Rice partitions; in total 2^partOrder partitions.
+ //
+ // ref: https://www.xiph.org/flac/format.html#rice_partition
+ // ref: https://www.xiph.org/flac/format.html#rice2_partition
+ partOrder := riceSubframe.PartOrder
+ nparts := 1 << partOrder
+ curResidualIndex := 0
+ for i := range riceSubframe.Partitions {
+ partition := &riceSubframe.Partitions[i]
+ // (4 or 5) bits: Rice parameter.
+ param := partition.Param
+ if err := bw.WriteBits(uint64(param), uint8(paramSize)); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Determine the number of Rice encoded samples in the partition.
+ var nsamples int
+ if partOrder == 0 {
+ nsamples = subframe.NSamples - subframe.Order
+ } else if i != 0 {
+ nsamples = subframe.NSamples / nparts
+ } else {
+ nsamples = subframe.NSamples/nparts - subframe.Order
+ }
+
+ if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F {
+ // 1111 or 11111: Escape code, meaning the partition is in unencoded
+ // binary form using n bits per sample; n follows as a 5-bit number.
+ if err := bw.WriteBits(uint64(partition.EscapedBitsPerSample), 5); err != nil {
+ return errutil.Err(err)
+ }
+ for j := 0; j < nsamples; j++ {
+ // ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/
+ //
+ // From section 9.2.7.1. Escaped partition:
+ //
+ // The residual samples themselves are stored signed two's
+ // complement. For example, when a partition is escaped and each
+ // residual sample is stored with 3 bits, the number -1 is
+ // represented as 0b111.
+ residual := residuals[curResidualIndex]
+ curResidualIndex++
+ if err := bw.WriteBits(uint64(residual), uint8(partition.EscapedBitsPerSample)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ continue
+ }
+
+ // Encode the Rice residuals of the partition.
+ for j := 0; j < nsamples; j++ {
+ residual := residuals[curResidualIndex]
+ curResidualIndex++
+ if err := encodeRiceResidual(bw, param, residual); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ }
+
+ return nil
+}
+
+// encodeRiceResidual encodes a Rice residual (error signal).
+func encodeRiceResidual(bw *bitio.Writer, k uint, residual int32) error {
+ // ZigZag encode.
+ folded := iobits.EncodeZigZag(residual)
+
+ // unfold into low- and high.
+ lowMask := ^uint32(0) >> (32 - k) // lower k bits.
+ highMask := ^uint32(0) << k // upper bits.
+ high := (folded & highMask) >> k
+ low := folded & lowMask
+
+ // Write unary encoded most significant bits.
+ if err := iobits.WriteUnary(bw, uint64(high)); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Write binary encoded least significant bits.
+ if err := bw.WriteBits(uint64(low), uint8(k)); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+}
+
+// getLPCResiduals returns the residuals (signal errors of the prediction)
+// between the given audio samples and the LPC predicted audio samples, using
+// the coefficients of a given polynomial, and a couple (order of polynomial;
+// i.e. len(coeffs)) of unencoded warm-up samples.
+func getLPCResiduals(subframe *frame.Subframe, coeffs []int32, shift int32) ([]int32, error) {
+ if len(coeffs) != subframe.Order {
+ return nil, fmt.Errorf("getLPCResiduals: prediction order (%d) differs from number of coefficients (%d)", subframe.Order, len(coeffs))
+ }
+ if shift < 0 {
+ return nil, fmt.Errorf("getLPCResiduals: invalid negative shift")
+ }
+ if subframe.NSamples != len(subframe.Samples) {
+ return nil, fmt.Errorf("getLPCResiduals: subframe sample count mismatch; expected %d, got %d", subframe.NSamples, len(subframe.Samples))
+ }
+ var residuals []int32
+ for i := subframe.Order; i < subframe.NSamples; i++ {
+ var sample int64
+ for j, c := range coeffs {
+ sample += int64(c) * int64(subframe.Samples[i-j-1])
+ }
+ residual := subframe.Samples[i] - int32(sample>>uint(shift))
+ residuals = append(residuals, residual)
+ }
+ return residuals, nil
+}
diff --git a/example_test.go b/example_test.go
new file mode 100755
index 0000000..55142c8
--- /dev/null
+++ b/example_test.go
@@ -0,0 +1,121 @@
+package flac_test
+
+import (
+ "bytes"
+ "crypto/md5"
+ "fmt"
+ "io"
+ "log"
+
+ "github.com/mewkiz/flac"
+)
+
+func ExampleParseFile() {
+ // Parse metadata of love.flac
+ stream, err := flac.ParseFile("testdata/love.flac")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer stream.Close()
+
+ fmt.Printf("unencoded audio md5sum: %032x\n", stream.Info.MD5sum[:])
+ for i, block := range stream.Blocks {
+ fmt.Printf("block %d: %v\n", i, block.Type)
+ }
+ // Output:
+ // unencoded audio md5sum: bdf6f7d31f77cb696a02b2192d192a89
+ // block 0: seek table
+ // block 1: vorbis comment
+ // block 2: padding
+}
+
+func ExampleOpen() {
+ // Open love.flac for audio streaming without parsing metadata.
+ stream, err := flac.Open("testdata/love.flac")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer stream.Close()
+
+ // Parse audio samples and verify the MD5 signature of the decoded audio
+ // samples.
+ md5sum := md5.New()
+ for {
+ // Parse one frame of audio samples at the time, each frame containing one
+ // subframe per audio channel.
+ frame, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ log.Fatal(err)
+ }
+ frame.Hash(md5sum)
+
+ // Print first three samples from each channel of the first five frames.
+ if frame.Num < 5 {
+ fmt.Printf("frame %d\n", frame.Num)
+ for i, subframe := range frame.Subframes {
+ fmt.Printf(" subframe %d\n", i)
+ for j, sample := range subframe.Samples {
+ if j >= 3 {
+ break
+ }
+ fmt.Printf(" sample %d: %v\n", j, sample)
+ }
+ }
+ }
+ }
+ fmt.Println()
+
+ got, want := md5sum.Sum(nil), stream.Info.MD5sum[:]
+ fmt.Println("decoded audio md5sum valid:", bytes.Equal(got, want))
+ // Output:
+ // frame 0
+ // subframe 0
+ // sample 0: 126
+ // sample 1: 126
+ // sample 2: 126
+ // subframe 1
+ // sample 0: 126
+ // sample 1: 126
+ // sample 2: 126
+ // frame 1
+ // subframe 0
+ // sample 0: 126
+ // sample 1: 126
+ // sample 2: 126
+ // subframe 1
+ // sample 0: 126
+ // sample 1: 126
+ // sample 2: 126
+ // frame 2
+ // subframe 0
+ // sample 0: 121
+ // sample 1: 130
+ // sample 2: 137
+ // subframe 1
+ // sample 0: 121
+ // sample 1: 130
+ // sample 2: 137
+ // frame 3
+ // subframe 0
+ // sample 0: -9501
+ // sample 1: -6912
+ // sample 2: -3916
+ // subframe 1
+ // sample 0: -9501
+ // sample 1: -6912
+ // sample 2: -3916
+ // frame 4
+ // subframe 0
+ // sample 0: 513
+ // sample 1: 206
+ // sample 2: 152
+ // subframe 1
+ // sample 0: 513
+ // sample 1: 206
+ // sample 2: 152
+ //
+ // decoded audio md5sum valid: true
+}
diff --git a/flac.go b/flac.go
new file mode 100755
index 0000000..d96f53e
--- /dev/null
+++ b/flac.go
@@ -0,0 +1,426 @@
+// TODO(u): Evaluate storing the samples (and residuals) during frame audio
+// decoding in a buffer allocated for the stream. This buffer would be allocated
+// using BlockSize and NChannels from the StreamInfo block, and it could be
+// reused in between calls to Next and ParseNext. This should reduce GC
+// pressure.
+
+// TODO: Remove note about encoder API.
+
+// Package flac provides access to FLAC (Free Lossless Audio Codec) streams.
+//
+// A brief introduction of the FLAC stream format [1] follows. Each FLAC stream
+// starts with a 32-bit signature ("fLaC"), followed by one or more metadata
+// blocks, and then one or more audio frames. The first metadata block
+// (StreamInfo) describes the basic properties of the audio stream and it is the
+// only mandatory metadata block. Subsequent metadata blocks may appear in an
+// arbitrary order.
+//
+// Please refer to the documentation of the meta [2] and the frame [3] packages
+// for a brief introduction of their respective formats.
+//
+// [1]: https://www.xiph.org/flac/format.html#stream
+// [2]: https://godoc.org/github.com/mewkiz/flac/meta
+// [3]: https://godoc.org/github.com/mewkiz/flac/frame
+//
+// Note: the Encoder API is experimental until the 1.1.x release. As such, it's
+// API is expected to change.
+package flac
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/mewkiz/flac/frame"
+ "github.com/mewkiz/flac/internal/bufseekio"
+ "github.com/mewkiz/flac/meta"
+)
+
+// A Stream contains the metadata blocks and provides access to the audio frames
+// of a FLAC stream.
+//
+// ref: https://www.xiph.org/flac/format.html#stream
+type Stream struct {
+ // The StreamInfo metadata block describes the basic properties of the FLAC
+ // audio stream.
+ Info *meta.StreamInfo
+ // Zero or more metadata blocks.
+ Blocks []*meta.Block
+
+ // seekTable contains one or more pre-calculated audio frame seek points of
+ // the stream; nil if uninitialized.
+ seekTable *meta.SeekTable
+ // seekTableSize determines how many seek points the seekTable should have if
+ // the flac file does not include one in the metadata.
+ seekTableSize int
+ // dataStart is the offset of the first frame header since SeekPoint.Offset
+ // is relative to this position.
+ dataStart int64
+
+ // Underlying io.Reader, or io.ReadCloser.
+ r io.Reader
+}
+
+// New creates a new Stream for accessing the audio samples of r. It reads and
+// parses the FLAC signature and the StreamInfo metadata block, but skips all
+// other metadata blocks.
+//
+// Call Stream.Next to parse the frame header of the next audio frame, and call
+// Stream.ParseNext to parse the entire next frame including audio samples.
+func New(r io.Reader) (stream *Stream, err error) {
+ // Verify FLAC signature and parse the StreamInfo metadata block.
+ br := bufio.NewReader(r)
+ stream = &Stream{r: br}
+ block, err := stream.parseStreamInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ // Skip the remaining metadata blocks.
+ for !block.IsLast {
+ block, err = meta.New(br)
+ if err != nil && err != meta.ErrReservedType {
+ return stream, err
+ }
+ if err = block.Skip(); err != nil {
+ return stream, err
+ }
+ }
+
+ return stream, nil
+}
+
+// NewSeek returns a Stream that has seeking enabled. The incoming io.ReadSeeker
+// will not be buffered, which might result in performance issues. Using an
+// in-memory buffer like *bytes.Reader should work well.
+func NewSeek(rs io.ReadSeeker) (stream *Stream, err error) {
+ br := bufseekio.NewReadSeeker(rs)
+ stream = &Stream{r: br, seekTableSize: defaultSeekTableSize}
+
+ // Verify FLAC signature and parse the StreamInfo metadata block.
+ block, err := stream.parseStreamInfo()
+ if err != nil {
+ return stream, err
+ }
+
+ for !block.IsLast {
+ block, err = meta.Parse(stream.r)
+ if err != nil {
+ if err != meta.ErrReservedType {
+ return stream, err
+ }
+ if err = block.Skip(); err != nil {
+ return stream, err
+ }
+ }
+
+ if block.Header.Type == meta.TypeSeekTable {
+ stream.seekTable = block.Body.(*meta.SeekTable)
+ }
+ }
+
+ // Record file offset of the first frame header.
+ stream.dataStart, err = br.Seek(0, io.SeekCurrent)
+ return stream, err
+}
+
+var (
+ // flacSignature marks the beginning of a FLAC stream.
+ flacSignature = []byte("fLaC")
+
+ // id3Signature marks the beginning of an ID3 stream, used to skip over ID3
+ // data.
+ id3Signature = []byte("ID3")
+
+ // ErrNoSeeker reports that flac.NewSeek was called with an io.Reader not
+ // implementing io.Seeker, and thus does not allow for seeking.
+ ErrNoSeeker = errors.New("stream.Seek: reader does not implement io.Seeker")
+
+ // ErrNoSeektable reports that no seektable has been generated. Therefore,
+ // it is not possible to seek in the stream.
+ ErrNoSeektable = errors.New("stream.searchFromStart: no seektable exists")
+)
+
+const (
+ defaultSeekTableSize = 100
+)
+
+// parseStreamInfo verifies the signature which marks the beginning of a FLAC
+// stream, and parses the StreamInfo metadata block. It returns a boolean value
+// which specifies if the StreamInfo block was the last metadata block of the
+// FLAC stream.
+func (stream *Stream) parseStreamInfo() (block *meta.Block, err error) {
+ // Verify FLAC signature.
+ r := stream.r
+ var buf [4]byte
+ if _, err = io.ReadFull(r, buf[:]); err != nil {
+ return block, err
+ }
+
+ // Skip prepended ID3v2 data.
+ if bytes.Equal(buf[:3], id3Signature) {
+ if err := stream.skipID3v2(); err != nil {
+ return block, err
+ }
+
+ // Second attempt at verifying signature.
+ if _, err = io.ReadFull(r, buf[:]); err != nil {
+ return block, err
+ }
+ }
+
+ if !bytes.Equal(buf[:], flacSignature) {
+ return block, fmt.Errorf("flac.parseStreamInfo: invalid FLAC signature; expected %q, got %q", flacSignature, buf)
+ }
+
+ // Parse StreamInfo metadata block.
+ block, err = meta.Parse(r)
+ if err != nil {
+ return block, err
+ }
+ si, ok := block.Body.(*meta.StreamInfo)
+ if !ok {
+ return block, fmt.Errorf("flac.parseStreamInfo: incorrect type of first metadata block; expected *meta.StreamInfo, got %T", block.Body)
+ }
+ stream.Info = si
+ return block, nil
+}
+
+// skipID3v2 skips ID3v2 data prepended to flac files.
+func (stream *Stream) skipID3v2() error {
+ r := bufio.NewReader(stream.r)
+
+ // Discard unnecessary data from the ID3v2 header.
+ if _, err := r.Discard(2); err != nil {
+ return err
+ }
+
+ // Read the size from the ID3v2 header.
+ var sizeBuf [4]byte
+ if _, err := r.Read(sizeBuf[:]); err != nil {
+ return err
+ }
+ // The size is encoded as a synchsafe integer.
+ size := int(sizeBuf[0])<<21 | int(sizeBuf[1])<<14 | int(sizeBuf[2])<<7 | int(sizeBuf[3])
+
+ _, err := r.Discard(size)
+ return err
+}
+
+// Parse creates a new Stream for accessing the metadata blocks and audio
+// samples of r. It reads and parses the FLAC signature and all metadata blocks.
+//
+// Call Stream.Next to parse the frame header of the next audio frame, and call
+// Stream.ParseNext to parse the entire next frame including audio samples.
+func Parse(r io.Reader) (stream *Stream, err error) {
+ // Verify FLAC signature and parse the StreamInfo metadata block.
+ br := bufio.NewReader(r)
+ stream = &Stream{r: br}
+ block, err := stream.parseStreamInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ // Parse the remaining metadata blocks.
+ for !block.IsLast {
+ block, err = meta.Parse(br)
+ if err != nil {
+ if err != meta.ErrReservedType {
+ return stream, err
+ }
+ // Skip the body of unknown (reserved) metadata blocks, as stated by
+ // the specification.
+ //
+ // ref: https://www.xiph.org/flac/format.html#format_overview
+ if err = block.Skip(); err != nil {
+ return stream, err
+ }
+ }
+ stream.Blocks = append(stream.Blocks, block)
+ }
+
+ return stream, nil
+}
+
+// Open creates a new Stream for accessing the audio samples of path. It reads
+// and parses the FLAC signature and the StreamInfo metadata block, but skips
+// all other metadata blocks.
+//
+// Call Stream.Next to parse the frame header of the next audio frame, and call
+// Stream.ParseNext to parse the entire next frame including audio samples.
+//
+// Note: The Close method of the stream must be called when finished using it.
+func Open(path string) (stream *Stream, err error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+
+ stream, err = New(f)
+ if err != nil {
+ return nil, err
+ }
+
+ return stream, err
+}
+
+// ParseFile creates a new Stream for accessing the metadata blocks and audio
+// samples of path. It reads and parses the FLAC signature and all metadata
+// blocks.
+//
+// Call Stream.Next to parse the frame header of the next audio frame, and call
+// Stream.ParseNext to parse the entire next frame including audio samples.
+//
+// Note: The Close method of the stream must be called when finished using it.
+func ParseFile(path string) (stream *Stream, err error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ stream, err = Parse(f)
+ if err != nil {
+ return nil, err
+ }
+
+ return stream, err
+}
+
+// Close closes the stream gracefully if the underlying io.Reader also implements the io.Closer interface.
+func (stream *Stream) Close() error {
+ if closer, ok := stream.r.(io.Closer); ok {
+ return closer.Close()
+ }
+
+ return nil
+}
+
+// Next parses the frame header of the next audio frame. It returns io.EOF to
+// signal a graceful end of FLAC stream.
+//
+// Call Frame.Parse to parse the audio samples of its subframes.
+func (stream *Stream) Next() (f *frame.Frame, err error) {
+ return frame.New(stream.r)
+}
+
+// ParseNext parses the entire next frame including audio samples. It returns
+// io.EOF to signal a graceful end of FLAC stream.
+func (stream *Stream) ParseNext() (f *frame.Frame, err error) {
+ return frame.Parse(stream.r)
+}
+
+// Seek seeks to the frame containing the given absolute sample number. The
+// return value specifies the first sample number of the frame containing
+// sampleNum.
+func (stream *Stream) Seek(sampleNum uint64) (uint64, error) {
+ if stream.seekTable == nil && stream.seekTableSize > 0 {
+ if err := stream.makeSeekTable(); err != nil {
+ return 0, err
+ }
+ }
+
+ rs := stream.r.(io.ReadSeeker)
+
+ isBiggerThanStream := stream.Info.NSamples != 0 && sampleNum >= stream.Info.NSamples
+ if isBiggerThanStream || sampleNum < 0 {
+ return 0, fmt.Errorf("unable to seek to sample number %d", sampleNum)
+ }
+ point, err := stream.searchFromStart(sampleNum)
+ if err != nil {
+ return 0, err
+ }
+
+ if _, err := rs.Seek(stream.dataStart+int64(point.Offset), io.SeekStart); err != nil {
+ return 0, err
+ }
+ for {
+ // Record seek offset to start of frame.
+ offset, err := rs.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return 0, err
+ }
+ frame, err := stream.ParseNext()
+ if err != nil {
+ return 0, err
+ }
+ if frame.SampleNumber()+uint64(frame.BlockSize) > sampleNum {
+ // Restore seek offset to the start of the frame containing the
+ // specified sample number.
+ _, err := rs.Seek(offset, io.SeekStart)
+ return frame.SampleNumber(), err
+ }
+ }
+}
+
+// TODO(_): Utilize binary search in searchFromStart.
+
+// searchFromStart searches for the given sample number from the start of the
+// seek table and returns the last seek point containing the sample number. If
+// no seek point contains the sample number, the last seek point preceding the
+// sample number is returned. If the sample number is lower than the first seek
+// point, the first seek point is returned.
+func (stream *Stream) searchFromStart(sampleNum uint64) (meta.SeekPoint, error) {
+ if len(stream.seekTable.Points) == 0 {
+ return meta.SeekPoint{}, ErrNoSeektable
+ }
+ prev := stream.seekTable.Points[0]
+ for _, p := range stream.seekTable.Points {
+ if p.SampleNum+uint64(p.NSamples) >= sampleNum {
+ return prev, nil
+ }
+ prev = p
+ }
+ return prev, nil
+}
+
+// makeSeekTable creates a seek table with seek points to each frame of the FLAC
+// stream.
+func (stream *Stream) makeSeekTable() (err error) {
+ rs, ok := stream.r.(io.ReadSeeker)
+ if !ok {
+ return ErrNoSeeker
+ }
+
+ pos, err := rs.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return err
+ }
+
+ _, err = rs.Seek(stream.dataStart, io.SeekStart)
+ if err != nil {
+ return err
+ }
+
+ var i int
+ var sampleNum uint64
+ var points []meta.SeekPoint
+ for {
+ // Record seek offset to start of frame.
+ off, err := rs.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return err
+ }
+ f, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+ points = append(points, meta.SeekPoint{
+ SampleNum: sampleNum,
+ Offset: uint64(off - stream.dataStart),
+ NSamples: f.BlockSize,
+ })
+
+ sampleNum += uint64(f.BlockSize)
+ i++
+ }
+
+ stream.seekTable = &meta.SeekTable{Points: points}
+
+ _, err = rs.Seek(pos, io.SeekStart)
+ return err
+}
diff --git a/flac_test.go b/flac_test.go
new file mode 100755
index 0000000..0783caf
--- /dev/null
+++ b/flac_test.go
@@ -0,0 +1,202 @@
+package flac_test
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "testing"
+
+ "github.com/mewkiz/flac"
+)
+
+func TestSkipID3v2(t *testing.T) {
+ if _, err := flac.ParseFile("testdata/id3.flac"); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestSeek(t *testing.T) {
+ f, err := os.Open("testdata/172960.flac")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer f.Close()
+
+ //Seek Table:
+ // {SampleNum:0 Offset:8283 NSamples:4096}
+ // {SampleNum:4096 Offset:17777 NSamples:4096}
+ // {SampleNum:8192 Offset:27141 NSamples:4096}
+ // {SampleNum:12288 Offset:36665 NSamples:4096}
+ // {SampleNum:16384 Offset:46179 NSamples:4096}
+ // {SampleNum:20480 Offset:55341 NSamples:4096}
+ // {SampleNum:24576 Offset:64690 NSamples:4096}
+ // {SampleNum:28672 Offset:74269 NSamples:4096}
+ // {SampleNum:32768 Offset:81984 NSamples:4096}
+ // {SampleNum:36864 Offset:86656 NSamples:4096}
+ // {SampleNum:40960 Offset:89596 NSamples:2723}
+
+ testPos := []struct {
+ seek uint64
+ expected uint64
+ err string
+ }{
+ {seek: 0, expected: 0},
+ {seek: 9000, expected: 8192},
+ {seek: 0, expected: 0},
+ {seek: 8000, expected: 4096},
+ {seek: 0, expected: 0},
+ {seek: 50000, expected: 0, err: "unable to seek to sample number 50000"},
+ {seek: 100, expected: 0},
+ {seek: 8192, expected: 8192},
+ {seek: 8191, expected: 4096},
+ //{seek: 40960 + 2723 - 1, expected: 40960}, // last sample // TODO: re-enable when it works. See https://github.com/mewkiz/flac/pull/73
+ {seek: 40960 + 2723, expected: 0, err: "unable to seek to sample number 43683"}, // one after last sample
+ }
+
+ stream, err := flac.NewSeek(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for i, pos := range testPos {
+ t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
+ p, err := stream.Seek(pos.seek)
+ if err != nil {
+ if err.Error() != pos.err {
+ t.Fatal(err)
+ }
+ }
+
+ if p != pos.expected {
+ t.Fatalf("pos %d does not equal %d", p, pos.expected)
+ }
+
+ _, err = stream.ParseNext()
+ if err != nil && err != io.EOF {
+ t.Fatal(err)
+ }
+ })
+
+ }
+}
+
+func TestDecode(t *testing.T) {
+ paths := []string{
+ "meta/testdata/input-SCPAP.flac",
+ "meta/testdata/input-SCVA.flac",
+ "meta/testdata/input-SCVPAP.flac",
+ "meta/testdata/input-VA.flac",
+ "meta/testdata/silence.flac",
+ "testdata/19875.flac",
+ "testdata/44127.flac",
+ "testdata/59996.flac",
+ "testdata/80574.flac",
+ "testdata/172960.flac",
+ "testdata/189983.flac",
+ "testdata/191885.flac",
+ "testdata/212768.flac",
+ "testdata/220014.flac",
+ "testdata/243749.flac",
+ "testdata/256529.flac",
+ "testdata/257344.flac",
+ "testdata/8297-275156-0011.flac",
+ "testdata/love.flac",
+ // IETF test cases.
+ //
+ // ref: https://github.com/ietf-wg-cellar/flac-test-files/tree/main/subset
+ "testdata/flac-test-files/subset/01 - blocksize 4096.flac",
+ "testdata/flac-test-files/subset/02 - blocksize 4608.flac",
+ "testdata/flac-test-files/subset/03 - blocksize 16.flac",
+ "testdata/flac-test-files/subset/04 - blocksize 192.flac",
+ "testdata/flac-test-files/subset/05 - blocksize 254.flac",
+ "testdata/flac-test-files/subset/06 - blocksize 512.flac",
+ "testdata/flac-test-files/subset/07 - blocksize 725.flac",
+ "testdata/flac-test-files/subset/08 - blocksize 1000.flac",
+ "testdata/flac-test-files/subset/09 - blocksize 1937.flac",
+ "testdata/flac-test-files/subset/10 - blocksize 2304.flac",
+ "testdata/flac-test-files/subset/11 - partition order 8.flac",
+ "testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac",
+ "testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac",
+ "testdata/flac-test-files/subset/14 - wasted bits.flac",
+ "testdata/flac-test-files/subset/15 - only verbatim subframes.flac",
+ "testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
+ "testdata/flac-test-files/subset/17 - all fixed orders.flac",
+ "testdata/flac-test-files/subset/18 - precision search.flac",
+ "testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac",
+ "testdata/flac-test-files/subset/20 - samplerate 39kHz.flac",
+ "testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac",
+ "testdata/flac-test-files/subset/22 - 12 bit per sample.flac",
+ "testdata/flac-test-files/subset/23 - 8 bit per sample.flac",
+ "testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac",
+ "testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac",
+ "testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac",
+ "testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac",
+ "testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac",
+ "testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac",
+ "testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac",
+ "testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
+ "testdata/flac-test-files/subset/33 - samplerate 192kHz.flac",
+ "testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac",
+ "testdata/flac-test-files/subset/36 - samplerate 384kHz.flac",
+ "testdata/flac-test-files/subset/37 - 20 bit per sample.flac",
+ "testdata/flac-test-files/subset/38 - 3 channels (3.0).flac",
+ "testdata/flac-test-files/subset/39 - 4 channels (4.0).flac",
+ "testdata/flac-test-files/subset/40 - 5 channels (5.0).flac",
+ "testdata/flac-test-files/subset/41 - 6 channels (5.1).flac",
+ "testdata/flac-test-files/subset/42 - 7 channels (6.1).flac",
+ "testdata/flac-test-files/subset/43 - 8 channels (7.1).flac",
+ "testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac",
+ "testdata/flac-test-files/subset/45 - no total number of samples set.flac",
+ "testdata/flac-test-files/subset/46 - no min-max framesize set.flac",
+ "testdata/flac-test-files/subset/47 - only STREAMINFO.flac",
+ "testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac",
+ "testdata/flac-test-files/subset/49 - Extremely large PADDING.flac",
+ "testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac",
+ "testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac",
+ "testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac",
+ "testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac",
+ "testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac",
+ "testdata/flac-test-files/subset/55 - file 48-53 combined.flac",
+ "testdata/flac-test-files/subset/56 - JPG PICTURE.flac",
+ "testdata/flac-test-files/subset/57 - PNG PICTURE.flac",
+ "testdata/flac-test-files/subset/58 - GIF PICTURE.flac",
+ "testdata/flac-test-files/subset/59 - AVIF PICTURE.flac",
+ "testdata/flac-test-files/subset/60 - mono audio.flac",
+ "testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac",
+ "testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac",
+ "testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac",
+ "testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
+ }
+
+ funcs := map[string]func(io.Reader) (*flac.Stream, error){
+ "new": flac.New,
+ "newSeek": func(r io.Reader) (*flac.Stream, error) { return flac.NewSeek(r.(io.ReadSeeker)) },
+ "parse": flac.Parse,
+ }
+
+ for _, path := range paths {
+ for k, f := range funcs {
+ t.Run(fmt.Sprintf("%s/%s", k, path), func(t *testing.T) {
+ file, err := os.Open(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stream, err := f(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = stream.ParseNext()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ file.Close()
+ })
+ }
+ }
+}
diff --git a/frame/frame.go b/frame/frame.go
new file mode 100755
index 0000000..877569a
--- /dev/null
+++ b/frame/frame.go
@@ -0,0 +1,687 @@
+// Package frame implements access to FLAC audio frames.
+//
+// A brief introduction of the FLAC audio format [1] follows. FLAC encoders
+// divide the audio stream into blocks through a process called blocking [2]. A
+// block contains the unencoded audio samples from all channels during a short
+// period of time. Each audio block is divided into subblocks, one per channel.
+//
+// There is often a correlation between the left and right channel of stereo
+// audio. Using inter-channel decorrelation [3] it is possible to store only one
+// of the channels and the difference between the channels, or store the average
+// of the channels and their difference. An encoder decorrelates audio samples
+// as follows:
+//
+// mid = (left + right)/2 // average of the channels
+// side = left - right // difference between the channels
+//
+// The blocks are encoded using a variety of prediction methods [4][5] and
+// stored in frames. Blocks and subblocks contains unencoded audio samples while
+// frames and subframes contain encoded audio samples. A FLAC stream contains
+// one or more audio frames.
+//
+// [1]: https://www.xiph.org/flac/format.html#architecture
+// [2]: https://www.xiph.org/flac/format.html#blocking
+// [3]: https://www.xiph.org/flac/format.html#interchannel
+// [4]: https://www.xiph.org/flac/format.html#prediction
+// [5]: https://godoc.org/github.com/mewkiz/flac/frame#Pred
+package frame
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "log"
+
+ "github.com/mewkiz/flac/internal/bits"
+ "github.com/mewkiz/flac/internal/hashutil"
+ "github.com/mewkiz/flac/internal/hashutil/crc16"
+ "github.com/mewkiz/flac/internal/hashutil/crc8"
+ "github.com/mewkiz/flac/internal/utf8"
+)
+
+// A Frame contains the header and subframes of an audio frame. It holds the
+// encoded samples from a block (a part) of the audio stream. Each subframe
+// holding the samples from one of its channel.
+//
+// ref: https://www.xiph.org/flac/format.html#frame
+type Frame struct {
+ // Audio frame header.
+ Header
+ // One subframe per channel, containing encoded audio samples.
+ Subframes []*Subframe
+ // CRC-16 hash sum, calculated by read operations on hr.
+ crc hashutil.Hash16
+ // A bit reader, wrapping read operations to hr.
+ br *bits.Reader
+ // A CRC-16 hash reader, wrapping read operations to r.
+ hr io.Reader
+ // Underlying io.Reader.
+ r io.Reader
+}
+
+// New creates a new Frame for accessing the audio samples of r. It reads and
+// parses an audio frame header. It returns io.EOF to signal a graceful end of
+// FLAC stream.
+//
+// Call Frame.Parse to parse the audio samples of its subframes.
+func New(r io.Reader) (frame *Frame, err error) {
+ // Create a new CRC-16 hash reader which adds the data from all read
+ // operations to a running hash.
+ crc := crc16.NewIBM()
+ hr := io.TeeReader(r, crc)
+
+ // Parse frame header.
+ frame = &Frame{crc: crc, hr: hr, r: r}
+ err = frame.parseHeader()
+ return frame, err
+}
+
+// Parse reads and parses the header, and the audio samples from each subframe
+// of a frame. If the samples are inter-channel decorrelated between the
+// subframes, it correlates them. It returns io.EOF to signal a graceful end of
+// FLAC stream.
+//
+// ref: https://www.xiph.org/flac/format.html#interchannel
+func Parse(r io.Reader) (frame *Frame, err error) {
+ // Parse frame header.
+ frame, err = New(r)
+ if err != nil {
+ return frame, err
+ }
+
+ // Parse subframes.
+ err = frame.Parse()
+ return frame, err
+}
+
+// Parse reads and parses the audio samples from each subframe of the frame. If
+// the samples are inter-channel decorrelated between the subframes, it
+// correlates them.
+//
+// ref: https://www.xiph.org/flac/format.html#interchannel
+func (frame *Frame) Parse() error {
+ // Parse subframes.
+ frame.Subframes = make([]*Subframe, frame.Channels.Count())
+ var err error
+ for channel := range frame.Subframes {
+ // The side channel requires an extra bit per sample when using
+ // inter-channel decorrelation.
+ bps := uint(frame.BitsPerSample)
+ switch frame.Channels {
+ case ChannelsSideRight:
+ // channel 0 is the side channel.
+ if channel == 0 {
+ bps++
+ }
+ case ChannelsLeftSide, ChannelsMidSide:
+ // channel 1 is the side channel.
+ if channel == 1 {
+ bps++
+ }
+ }
+
+ // Parse subframe.
+ frame.Subframes[channel], err = frame.parseSubframe(frame.br, bps)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Inter-channel correlation of subframe samples.
+ frame.Correlate()
+
+ // 2 bytes: CRC-16 checksum.
+ var want uint16
+ if err = binary.Read(frame.r, binary.BigEndian, &want); err != nil {
+ return unexpected(err)
+ }
+ got := frame.crc.Sum16()
+ if got != want {
+ return fmt.Errorf("frame.Frame.Parse: CRC-16 checksum mismatch; expected 0x%04X, got 0x%04X", want, got)
+ }
+
+ return nil
+}
+
+// Hash adds the decoded audio samples of the frame to a running MD5 hash. It
+// can be used in conjunction with StreamInfo.MD5sum to verify the integrity of
+// the decoded audio samples.
+//
+// Note: The audio samples of the frame must be decoded before calling Hash.
+func (frame *Frame) Hash(md5sum hash.Hash) {
+ // Write decoded samples to a running MD5 hash.
+ bps := frame.BitsPerSample
+ var buf [3]byte
+ for i := 0; i < int(frame.BlockSize); i++ {
+ for _, subframe := range frame.Subframes {
+ sample := subframe.Samples[i]
+ switch {
+ case 1 <= bps && bps <= 8:
+ buf[0] = uint8(sample)
+ md5sum.Write(buf[:1])
+ case 9 <= bps && bps <= 16:
+ buf[0] = uint8(sample)
+ buf[1] = uint8(sample >> 8)
+ md5sum.Write(buf[:2])
+ case 17 <= bps && bps <= 24:
+ buf[0] = uint8(sample)
+ buf[1] = uint8(sample >> 8)
+ buf[2] = uint8(sample >> 16)
+ md5sum.Write(buf[:])
+ default:
+ log.Printf("frame.Frame.Hash: support for %d-bit sample size not yet implemented", bps)
+ }
+ }
+ }
+}
+
+// A Header contains the basic properties of an audio frame, such as its sample
+// rate and channel count. To facilitate random access decoding each frame
+// header starts with a sync-code. This allows the decoder to synchronize and
+// locate the start of a frame header.
+//
+// ref: https://www.xiph.org/flac/format.html#frame_header
+type Header struct {
+ // Specifies if the block size is fixed or variable.
+ HasFixedBlockSize bool
+ // Block size in inter-channel samples, i.e. the number of audio samples in
+ // each subframe.
+ BlockSize uint16
+ // Sample rate in Hz; a 0 value implies unknown, get sample rate from
+ // StreamInfo.
+ SampleRate uint32
+ // Specifies the number of channels (subframes) that exist in the frame,
+ // their order and possible inter-channel decorrelation.
+ Channels Channels
+ // Sample size in bits-per-sample; a 0 value implies unknown, get sample size
+ // from StreamInfo.
+ BitsPerSample uint8
+ // Specifies the frame number if the block size is fixed, and the first
+ // sample number in the frame otherwise. When using fixed block size, the
+ // first sample number in the frame can be derived by multiplying the frame
+ // number with the block size (in samples).
+ Num uint64
+}
+
+// Errors returned by Frame.parseHeader.
+var (
+ ErrInvalidSync = errors.New("frame.Frame.parseHeader: invalid sync-code")
+)
+
+// parseHeader reads and parses the header of an audio frame.
+func (frame *Frame) parseHeader() error {
+ // Create a new CRC-8 hash reader which adds the data from all read
+ // operations to a running hash.
+ h := crc8.NewATM()
+ hr := io.TeeReader(frame.hr, h)
+
+ // Create bit reader.
+ br := bits.NewReader(hr)
+ frame.br = br
+
+ // 14 bits: sync-code (11111111111110)
+ x, err := br.Read(14)
+ if err != nil {
+ // This is the only place an audio frame may return io.EOF, which signals
+ // a graceful end of a FLAC stream.
+ return err
+ }
+ if x != 0x3FFE {
+ return ErrInvalidSync
+ }
+
+ // 1 bit: reserved.
+ x, err = br.Read(1)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x != 0 {
+ return errors.New("frame.Frame.parseHeader: non-zero reserved value")
+ }
+
+ // 1 bit: HasFixedBlockSize.
+ x, err = br.Read(1)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x == 0 {
+ frame.HasFixedBlockSize = true
+ }
+
+ // 4 bits: BlockSize. The block size parsing is simplified by deferring it to
+ // the end of the header.
+ blockSize, err := br.Read(4)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // 4 bits: SampleRate. The sample rate parsing is simplified by deferring it
+ // to the end of the header.
+ sampleRate, err := br.Read(4)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // Parse channels.
+ if err := frame.parseChannels(br); err != nil {
+ return err
+ }
+
+ // Parse bits per sample.
+ if err := frame.parseBitsPerSample(br); err != nil {
+ return err
+ }
+
+ // 1 bit: reserved.
+ x, err = br.Read(1)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x != 0 {
+ return errors.New("frame.Frame.parseHeader: non-zero reserved value")
+ }
+
+ // if (fixed block size)
+ // 1-6 bytes: UTF-8 encoded frame number.
+ // else
+ // 1-7 bytes: UTF-8 encoded sample number.
+ frame.Num, err = utf8.Decode(hr)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // Parse block size.
+ if err := frame.parseBlockSize(br, blockSize); err != nil {
+ return err
+ }
+
+ // Parse sample rate.
+ if err := frame.parseSampleRate(br, sampleRate); err != nil {
+ return err
+ }
+
+ // 1 byte: CRC-8 checksum.
+ var want uint8
+ if err = binary.Read(frame.hr, binary.BigEndian, &want); err != nil {
+ return unexpected(err)
+ }
+ got := h.Sum8()
+ if want != got {
+ return fmt.Errorf("frame.Frame.parseHeader: CRC-8 checksum mismatch; expected 0x%02X, got 0x%02X", want, got)
+ }
+
+ return nil
+}
+
+// parseBitsPerSample parses the bits per sample of the header.
+func (frame *Frame) parseBitsPerSample(br *bits.Reader) error {
+ // 3 bits: BitsPerSample.
+ x, err := br.Read(3)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // The 3 bits are used to specify the sample size as follows:
+ // 000: unknown sample size; get from StreamInfo.
+ // 001: 8 bits-per-sample.
+ // 010: 12 bits-per-sample.
+ // 011: reserved.
+ // 100: 16 bits-per-sample.
+ // 101: 20 bits-per-sample.
+ // 110: 24 bits-per-sample.
+ // 111: reserved.
+ switch x {
+ case 0x0:
+ // 000: unknown bits-per-sample; get from StreamInfo.
+ case 0x1:
+ // 001: 8 bits-per-sample.
+ frame.BitsPerSample = 8
+ case 0x2:
+ // 010: 12 bits-per-sample.
+ frame.BitsPerSample = 12
+ case 0x4:
+ // 100: 16 bits-per-sample.
+ frame.BitsPerSample = 16
+ case 0x5:
+ // 101: 20 bits-per-sample.
+ frame.BitsPerSample = 20
+ case 0x6:
+ // 110: 24 bits-per-sample.
+ frame.BitsPerSample = 24
+ default:
+ // 011: reserved.
+ // 111: reserved.
+ return fmt.Errorf("frame.Frame.parseHeader: reserved sample size bit pattern (%03b)", x)
+ }
+ return nil
+}
+
+// parseChannels parses the channels of the header.
+func (frame *Frame) parseChannels(br *bits.Reader) error {
+ // 4 bits: Channels.
+ //
+ // The 4 bits are used to specify the channels as follows:
+ // 0000: (1 channel) mono.
+ // 0001: (2 channels) left, right.
+ // 0010: (3 channels) left, right, center.
+ // 0011: (4 channels) left, right, left surround, right surround.
+ // 0100: (5 channels) left, right, center, left surround, right surround.
+ // 0101: (6 channels) left, right, center, LFE, left surround, right surround.
+ // 0110: (7 channels) left, right, center, LFE, center surround, side left, side right.
+ // 0111: (8 channels) left, right, center, LFE, left surround, right surround, side left, side right.
+ // 1000: (2 channels) left, side; using inter-channel decorrelation.
+ // 1001: (2 channels) side, right; using inter-channel decorrelation.
+ // 1010: (2 channels) mid, side; using inter-channel decorrelation.
+ // 1011: reserved.
+ // 1100: reserved.
+ // 1101: reserved.
+ // 1111: reserved.
+ x, err := br.Read(4)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x >= 0xB {
+ return fmt.Errorf("frame.Frame.parseHeader: reserved channels bit pattern (%04b)", x)
+ }
+ frame.Channels = Channels(x)
+ return nil
+}
+
+// parseBlockSize parses the block size of the header.
+func (frame *Frame) parseBlockSize(br *bits.Reader, blockSize uint64) error {
+ // The 4 bits of n are used to specify the block size as follows:
+ // 0000: reserved.
+ // 0001: 192 samples.
+ // 0010-0101: 576 * 2^(n-2) samples.
+ // 0110: get 8 bit (block size)-1 from the end of the header.
+ // 0111: get 16 bit (block size)-1 from the end of the header.
+ // 1000-1111: 256 * 2^(n-8) samples.
+ n := blockSize
+ switch {
+ case n == 0x0:
+ // 0000: reserved.
+ return errors.New("frame.Frame.parseHeader: reserved block size bit pattern (0000)")
+ case n == 0x1:
+ // 0001: 192 samples.
+ frame.BlockSize = 192
+ case n >= 0x2 && n <= 0x5:
+ // 0010-0101: 576 * 2^(n-2) samples.
+ frame.BlockSize = 576 * (1 << (n - 2))
+ case n == 0x6:
+ // 0110: get 8 bit (block size)-1 from the end of the header.
+ x, err := br.Read(8)
+ if err != nil {
+ return unexpected(err)
+ }
+ frame.BlockSize = uint16(x + 1)
+ case n == 0x7:
+ // 0111: get 16 bit (block size)-1 from the end of the header.
+ x, err := br.Read(16)
+ if err != nil {
+ return unexpected(err)
+ }
+ frame.BlockSize = uint16(x + 1)
+ default:
+ // 1000-1111: 256 * 2^(n-8) samples.
+ frame.BlockSize = 256 * (1 << (n - 8))
+ }
+ return nil
+}
+
+// parseSampleRate parses the sample rate of the header.
+func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64) error {
+ // The 4 bits are used to specify the sample rate as follows:
+ // 0000: unknown sample rate; get from StreamInfo.
+ // 0001: 88.2 kHz.
+ // 0010: 176.4 kHz.
+ // 0011: 192 kHz.
+ // 0100: 8 kHz.
+ // 0101: 16 kHz.
+ // 0110: 22.05 kHz.
+ // 0111: 24 kHz.
+ // 1000: 32 kHz.
+ // 1001: 44.1 kHz.
+ // 1010: 48 kHz.
+ // 1011: 96 kHz.
+ // 1100: get 8 bit sample rate (in kHz) from the end of the header.
+ // 1101: get 16 bit sample rate (in Hz) from the end of the header.
+ // 1110: get 16 bit sample rate (in daHz) from the end of the header.
+ // 1111: invalid.
+ switch sampleRate {
+ case 0x0:
+ // 0000: unknown sample rate; get from StreamInfo.
+ case 0x1:
+ // 0001: 88.2 kHz.
+ frame.SampleRate = 88200
+ case 0x2:
+ // 0010: 176.4 kHz.
+ frame.SampleRate = 176400
+ // TODO(u): Remove log message when the test cases have been extended.
+ log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate)
+ case 0x3:
+ // 0011: 192 kHz.
+ frame.SampleRate = 192000
+ case 0x4:
+ // 0100: 8 kHz.
+ frame.SampleRate = 8000
+ case 0x5:
+ // 0101: 16 kHz.
+ frame.SampleRate = 16000
+ case 0x6:
+ // 0110: 22.05 kHz.
+ frame.SampleRate = 22050
+ case 0x7:
+ // 0111: 24 kHz.
+ frame.SampleRate = 24000
+ // TODO(u): Remove log message when the test cases have been extended.
+ log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate)
+ case 0x8:
+ // 1000: 32 kHz.
+ frame.SampleRate = 32000
+ case 0x9:
+ // 1001: 44.1 kHz.
+ frame.SampleRate = 44100
+ case 0xA:
+ // 1010: 48 kHz.
+ frame.SampleRate = 48000
+ case 0xB:
+ // 1011: 96 kHz.
+ frame.SampleRate = 96000
+ case 0xC:
+ // 1100: get 8 bit sample rate (in kHz) from the end of the header.
+ x, err := br.Read(8)
+ if err != nil {
+ return unexpected(err)
+ }
+ frame.SampleRate = uint32(x * 1000)
+ case 0xD:
+ // 1101: get 16 bit sample rate (in Hz) from the end of the header.
+ x, err := br.Read(16)
+ if err != nil {
+ return unexpected(err)
+ }
+ frame.SampleRate = uint32(x)
+ case 0xE:
+ // 1110: get 16 bit sample rate (in daHz) from the end of the header.
+ x, err := br.Read(16)
+ if err != nil {
+ return unexpected(err)
+ }
+ frame.SampleRate = uint32(x * 10)
+ default:
+ // 1111: invalid.
+ return errors.New("frame.Frame.parseHeader: invalid sample rate bit pattern (1111)")
+ }
+ return nil
+}
+
+// Channels specifies the number of channels (subframes) that exist in a frame,
+// their order and possible inter-channel decorrelation.
+type Channels uint8
+
+// Channel assignments. The following abbreviations are used:
+//
+// C: center (directly in front)
+// R: right (standard stereo)
+// Sr: side right (directly to the right)
+// Rs: right surround (back right)
+// Cs: center surround (rear center)
+// Ls: left surround (back left)
+// Sl: side left (directly to the left)
+// L: left (standard stereo)
+// Lfe: low-frequency effect (placed according to room acoustics)
+//
+// The first 6 channel constants follow the SMPTE/ITU-R channel order:
+//
+// L R C Lfe Ls Rs
+const (
+ ChannelsMono Channels = iota // 1 channel: mono.
+ ChannelsLR // 2 channels: left, right.
+ ChannelsLRC // 3 channels: left, right, center.
+ ChannelsLRLsRs // 4 channels: left, right, left surround, right surround.
+ ChannelsLRCLsRs // 5 channels: left, right, center, left surround, right surround.
+ ChannelsLRCLfeLsRs // 6 channels: left, right, center, LFE, left surround, right surround.
+ ChannelsLRCLfeCsSlSr // 7 channels: left, right, center, LFE, center surround, side left, side right.
+ ChannelsLRCLfeLsRsSlSr // 8 channels: left, right, center, LFE, left surround, right surround, side left, side right.
+ ChannelsLeftSide // 2 channels: left, side; using inter-channel decorrelation.
+ ChannelsSideRight // 2 channels: side, right; using inter-channel decorrelation.
+ ChannelsMidSide // 2 channels: mid, side; using inter-channel decorrelation.
+)
+
+// nChannels specifies the number of channels used by each channel assignment.
+var nChannels = [...]int{
+ ChannelsMono: 1,
+ ChannelsLR: 2,
+ ChannelsLRC: 3,
+ ChannelsLRLsRs: 4,
+ ChannelsLRCLsRs: 5,
+ ChannelsLRCLfeLsRs: 6,
+ ChannelsLRCLfeCsSlSr: 7,
+ ChannelsLRCLfeLsRsSlSr: 8,
+ ChannelsLeftSide: 2,
+ ChannelsSideRight: 2,
+ ChannelsMidSide: 2,
+}
+
+// Count returns the number of channels (subframes) used by the provided channel
+// assignment.
+func (channels Channels) Count() int {
+ return nChannels[channels]
+}
+
+// Correlate reverts any inter-channel decorrelation between the samples of the
+// subframes.
+//
+// An encoder decorrelates audio samples as follows:
+//
+// mid = (left + right)/2
+// side = left - right
+func (frame *Frame) Correlate() {
+ switch frame.Channels {
+ case ChannelsLeftSide:
+ // 2 channels: left, side; using inter-channel decorrelation.
+ left := frame.Subframes[0].Samples
+ side := frame.Subframes[1].Samples
+ for i := range side {
+ // right = left - side
+ side[i] = left[i] - side[i]
+ }
+ case ChannelsSideRight:
+ // 2 channels: side, right; using inter-channel decorrelation.
+ side := frame.Subframes[0].Samples
+ right := frame.Subframes[1].Samples
+ for i := range side {
+ // left = right + side
+ side[i] = right[i] + side[i]
+ }
+ case ChannelsMidSide:
+ // 2 channels: mid, side; using inter-channel decorrelation.
+ mid := frame.Subframes[0].Samples
+ side := frame.Subframes[1].Samples
+ for i := range side {
+ // left = (2*mid + side)/2
+ // right = (2*mid - side)/2
+ m := mid[i]
+ s := side[i]
+ m *= 2
+ // Notice that the integer division in mid = (left + right)/2 discards
+ // the least significant bit. It can be reconstructed however, since a
+ // sum A+B and a difference A-B has the same least significant bit.
+ //
+ // ref: Data Compression: The Complete Reference (ch. 7, Decorrelation)
+ m |= s & 1
+ mid[i] = (m + s) / 2
+ side[i] = (m - s) / 2
+ }
+ }
+}
+
+// Decorrelate performs inter-channel decorrelation between the samples of the
+// subframes.
+//
+// An encoder decorrelates audio samples as follows:
+//
+// mid = (left + right)/2
+// side = left - right
+func (frame *Frame) Decorrelate() {
+ switch frame.Channels {
+ case ChannelsLeftSide:
+ // 2 channels: left, side; using inter-channel decorrelation.
+ left := frame.Subframes[0].Samples // already left; no change after inter-channel decorrelation.
+ right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation.
+ for i := range left {
+ l := left[i]
+ r := right[i]
+ // inter-channel decorrelation:
+ // side = left - right
+ side := l - r
+ right[i] = side
+ }
+ case ChannelsSideRight:
+ // 2 channels: side, right; using inter-channel decorrelation.
+ left := frame.Subframes[0].Samples // set to side after inter-channel decorrelation.
+ right := frame.Subframes[1].Samples // already right; no change after inter-channel decorrelation.
+ for i := range left {
+ l := left[i]
+ r := right[i]
+ // inter-channel decorrelation:
+ // side = left - right
+ side := l - r
+ left[i] = side
+ }
+ case ChannelsMidSide:
+ // 2 channels: mid, side; using inter-channel decorrelation.
+ left := frame.Subframes[0].Samples // set to mid after inter-channel decorrelation.
+ right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation.
+ for i := range left {
+ // inter-channel decorrelation:
+ // mid = (left + right)/2
+ // side = left - right
+ l := left[i]
+ r := right[i]
+ mid := int32((int64(l) + int64(r)) >> 1) // NOTE: using `(left + right) >> 1`, not the same as `(left + right) / 2`.
+ side := l - r
+ left[i] = mid
+ right[i] = side
+ }
+ }
+}
+
+// SampleNumber returns the first sample number contained within the frame.
+func (frame *Frame) SampleNumber() uint64 {
+ if frame.HasFixedBlockSize {
+ return frame.Num * uint64(frame.BlockSize)
+ }
+ return frame.Num
+}
+
+// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err
+// otherwise.
+func unexpected(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/frame/frame_test.go b/frame/frame_test.go
new file mode 100755
index 0000000..cf66425
--- /dev/null
+++ b/frame/frame_test.go
@@ -0,0 +1,193 @@
+package frame_test
+
+import (
+ "bytes"
+ "crypto/md5"
+ "io"
+ "testing"
+
+ "github.com/mewkiz/flac"
+)
+
+var golden = []struct {
+ path string
+}{
+ {path: "../testdata/love.flac"},
+ {path: "../testdata/19875.flac"},
+ {path: "../testdata/44127.flac"},
+ {path: "../testdata/59996.flac"},
+ {path: "../testdata/80574.flac"},
+ {path: "../testdata/172960.flac"},
+ {path: "../testdata/189983.flac"},
+ {path: "../testdata/191885.flac"},
+ {path: "../testdata/212768.flac"},
+ {path: "../testdata/220014.flac"},
+ {path: "../testdata/243749.flac"},
+ {path: "../testdata/256529.flac"},
+ {path: "../testdata/257344.flac"},
+
+ // IETF test cases.
+ {path: "../testdata/flac-test-files/subset/01 - blocksize 4096.flac"},
+ {path: "../testdata/flac-test-files/subset/02 - blocksize 4608.flac"},
+ {path: "../testdata/flac-test-files/subset/03 - blocksize 16.flac"},
+ {path: "../testdata/flac-test-files/subset/04 - blocksize 192.flac"},
+ {path: "../testdata/flac-test-files/subset/05 - blocksize 254.flac"},
+ {path: "../testdata/flac-test-files/subset/06 - blocksize 512.flac"},
+ {path: "../testdata/flac-test-files/subset/07 - blocksize 725.flac"},
+ {path: "../testdata/flac-test-files/subset/08 - blocksize 1000.flac"},
+ {path: "../testdata/flac-test-files/subset/09 - blocksize 1937.flac"},
+ {path: "../testdata/flac-test-files/subset/10 - blocksize 2304.flac"},
+ {path: "../testdata/flac-test-files/subset/11 - partition order 8.flac"},
+ {path: "../testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac"},
+ {path: "../testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac"},
+ {path: "../testdata/flac-test-files/subset/14 - wasted bits.flac"},
+ {path: "../testdata/flac-test-files/subset/15 - only verbatim subframes.flac"},
+ {path: "../testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac"},
+ {path: "../testdata/flac-test-files/subset/17 - all fixed orders.flac"},
+ {path: "../testdata/flac-test-files/subset/18 - precision search.flac"},
+ {path: "../testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac"},
+ {path: "../testdata/flac-test-files/subset/20 - samplerate 39kHz.flac"},
+ {path: "../testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac"},
+ {path: "../testdata/flac-test-files/subset/22 - 12 bit per sample.flac"},
+ {path: "../testdata/flac-test-files/subset/23 - 8 bit per sample.flac"},
+ {path: "../testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac"},
+ {path: "../testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac"},
+ {path: "../testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac"},
+ {path: "../testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac"},
+ {path: "../testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac"},
+ {path: "../testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac"},
+ {path: "../testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac"},
+ {path: "../testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac"},
+ {path: "../testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac"},
+ {path: "../testdata/flac-test-files/subset/33 - samplerate 192kHz.flac"},
+ {path: "../testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac"},
+ {path: "../testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac"},
+ {path: "../testdata/flac-test-files/subset/36 - samplerate 384kHz.flac"},
+ {path: "../testdata/flac-test-files/subset/37 - 20 bit per sample.flac"},
+ {path: "../testdata/flac-test-files/subset/38 - 3 channels (3.0).flac"},
+ {path: "../testdata/flac-test-files/subset/39 - 4 channels (4.0).flac"},
+ {path: "../testdata/flac-test-files/subset/40 - 5 channels (5.0).flac"},
+ {path: "../testdata/flac-test-files/subset/41 - 6 channels (5.1).flac"},
+ {path: "../testdata/flac-test-files/subset/42 - 7 channels (6.1).flac"},
+ {path: "../testdata/flac-test-files/subset/43 - 8 channels (7.1).flac"},
+ {path: "../testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac"},
+ {path: "../testdata/flac-test-files/subset/45 - no total number of samples set.flac"},
+ {path: "../testdata/flac-test-files/subset/46 - no min-max framesize set.flac"},
+ {path: "../testdata/flac-test-files/subset/47 - only STREAMINFO.flac"},
+ {path: "../testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac"},
+ {path: "../testdata/flac-test-files/subset/49 - Extremely large PADDING.flac"},
+ {path: "../testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac"},
+ {path: "../testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac"},
+ {path: "../testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac"},
+ {path: "../testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac"},
+ {path: "../testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac"},
+ {path: "../testdata/flac-test-files/subset/55 - file 48-53 combined.flac"},
+ {path: "../testdata/flac-test-files/subset/56 - JPG PICTURE.flac"},
+ {path: "../testdata/flac-test-files/subset/57 - PNG PICTURE.flac"},
+ {path: "../testdata/flac-test-files/subset/58 - GIF PICTURE.flac"},
+ {path: "../testdata/flac-test-files/subset/59 - AVIF PICTURE.flac"},
+ {path: "../testdata/flac-test-files/subset/60 - mono audio.flac"},
+ {path: "../testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac"},
+ {path: "../testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac"},
+ // TODO: fix decoding of "subset/63 - ...flac": MD5 checksum mismatch for decoded audio samples; expected e4e4a6b3a672a849a3e2157c11ad23c6, got a0343afaaaa6229266d78ccf3175eb8d
+ {path: "../testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac"},
+ {path: "../testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac"},
+}
+
+func TestFrameHash(t *testing.T) {
+ var zeroHash [md5.Size]byte
+ for _, g := range golden {
+ t.Run(g.path, func(t *testing.T) {
+ stream, err := flac.Open(g.path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stream.Close()
+
+ // Skip frame hash test if no MD5 hash was set in StreamInfo.
+ want := stream.Info.MD5sum[:]
+ if bytes.Equal(want, zeroHash[:]) {
+ t.Skipf("path=%q, skipping frame hash test as no MD5 hash was set in StreamInfo", g.path)
+ return
+ }
+
+ md5sum := md5.New()
+ for frameNum := 0; ; frameNum++ {
+ frame, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Errorf("path=%q, frameNum=%d: error while parsing frame; %v", g.path, frameNum, err)
+ continue
+ }
+ frame.Hash(md5sum)
+ }
+ got := md5sum.Sum(nil)
+ // Verify the decoded audio samples by comparing the MD5 checksum that is
+ // stored in StreamInfo with the computed one.
+ if !bytes.Equal(got, want) {
+ t.Errorf("path=%q: MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", g.path, want, got)
+ }
+ })
+ }
+}
+
+func BenchmarkFrameParse(b *testing.B) {
+ // The file 151185.flac is a 119.5 MB public domain FLAC file used to
+ // benchmark the flac library. Because of its size, it has not been included
+ // in the repository, but is available for download at
+ //
+ // http://freesound.org/people/jarfil/sounds/151185/
+ for i := 0; i < b.N; i++ {
+ stream, err := flac.Open("../testdata/benchmark/151185.flac")
+ if err != nil {
+ b.Fatal(err)
+ }
+ for {
+ _, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ stream.Close()
+ b.Fatal(err)
+ }
+ }
+ stream.Close()
+ }
+}
+
+func BenchmarkFrameHash(b *testing.B) {
+ // The file 151185.flac is a 119.5 MB public domain FLAC file used to
+ // benchmark the flac library. Because of its size, it has not been included
+ // in the repository, but is available for download at
+ //
+ // http://freesound.org/people/jarfil/sounds/151185/
+ for i := 0; i < b.N; i++ {
+ stream, err := flac.Open("../testdata/benchmark/151185.flac")
+ if err != nil {
+ b.Fatal(err)
+ }
+ md5sum := md5.New()
+ for {
+ frame, err := stream.ParseNext()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ stream.Close()
+ b.Fatal(err)
+ }
+ frame.Hash(md5sum)
+ }
+ stream.Close()
+ want := stream.Info.MD5sum[:]
+ got := md5sum.Sum(nil)
+ // Verify the decoded audio samples by comparing the MD5 checksum that is
+ // stored in StreamInfo with the computed one.
+ if !bytes.Equal(got, want) {
+ b.Fatalf("MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", want, got)
+ }
+ }
+}
diff --git a/frame/subframe.go b/frame/subframe.go
new file mode 100755
index 0000000..b906609
--- /dev/null
+++ b/frame/subframe.go
@@ -0,0 +1,534 @@
+package frame
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/mewkiz/flac/internal/bits"
+)
+
+// A Subframe contains the encoded audio samples from one channel of an audio
+// block (a part of the audio stream).
+//
+// ref: https://www.xiph.org/flac/format.html#subframe
+type Subframe struct {
+ // Subframe header.
+ SubHeader
+ // Unencoded audio samples. Samples is initially nil, and gets populated by a
+ // call to Frame.Parse.
+ //
+ // Samples is used by decodeFixed and decodeFIR to temporarily store
+ // residuals. Before returning they call decodeLPC which decodes the audio
+ // samples.
+ Samples []int32
+ // Number of audio samples in the subframe.
+ NSamples int
+}
+
+// parseSubframe reads and parses the header, and the audio samples of a
+// subframe.
+func (frame *Frame) parseSubframe(br *bits.Reader, bps uint) (subframe *Subframe, err error) {
+ // Parse subframe header.
+ subframe = new(Subframe)
+ if err = subframe.parseHeader(br); err != nil {
+ return subframe, err
+ }
+ // Adjust bps of subframe for wasted bits-per-sample.
+ bps -= subframe.Wasted
+
+ // Decode subframe audio samples.
+ subframe.NSamples = int(frame.BlockSize)
+ subframe.Samples = make([]int32, 0, subframe.NSamples)
+ switch subframe.Pred {
+ case PredConstant:
+ err = subframe.decodeConstant(br, bps)
+ case PredVerbatim:
+ err = subframe.decodeVerbatim(br, bps)
+ case PredFixed:
+ err = subframe.decodeFixed(br, bps)
+ case PredFIR:
+ err = subframe.decodeFIR(br, bps)
+ }
+
+ // Left shift to account for wasted bits-per-sample.
+ for i, sample := range subframe.Samples {
+ subframe.Samples[i] = sample << subframe.Wasted
+ }
+ return subframe, err
+}
+
+// A SubHeader specifies the prediction method and order of a subframe.
+//
+// ref: https://www.xiph.org/flac/format.html#subframe_header
+type SubHeader struct {
+ // Specifies the prediction method used to encode the audio sample of the
+ // subframe.
+ Pred Pred
+ // Prediction order used by fixed and FIR linear prediction decoding.
+ Order int
+ // Wasted bits-per-sample.
+ Wasted uint
+ // Residual coding method used by fixed and FIR linear prediction decoding.
+ ResidualCodingMethod ResidualCodingMethod
+ // Coefficients' precision in bits used by FIR linear prediction decoding.
+ CoeffPrec uint
+ // Predictor coefficient shift needed in bits used by FIR linear prediction
+ // decoding.
+ CoeffShift int32
+ // Predictor coefficients used by FIR linear prediction decoding.
+ Coeffs []int32
+ // Rice-coding subframe fields used by residual coding methods rice1 and
+ // rice2; nil if unused.
+ RiceSubframe *RiceSubframe
+}
+
+// RiceSubframe holds rice-coding subframe fields used by residual coding
+// methods rice1 and rice2.
+type RiceSubframe struct {
+ // Partition order used by fixed and FIR linear prediction decoding
+ // (for residual coding methods, rice1 and rice2).
+ PartOrder int // TODO: remove PartOrder and infer from int(math.Log2(float64(len(Partitions))))?
+ // Rice partitions.
+ Partitions []RicePartition
+}
+
+// RicePartition is a partition containing a subset of the residuals of a
+// subframe.
+type RicePartition struct {
+ // Rice parameter.
+ Param uint
+ // Residual sample size in bits-per-sample used by escaped partitions.
+ EscapedBitsPerSample uint
+}
+
+// parseHeader reads and parses the header of a subframe.
+func (subframe *Subframe) parseHeader(br *bits.Reader) error {
+ // 1 bit: zero-padding.
+ x, err := br.Read(1)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x != 0 {
+ return errors.New("frame.Subframe.parseHeader: non-zero padding")
+ }
+
+ // 6 bits: Pred.
+ x, err = br.Read(6)
+ if err != nil {
+ return unexpected(err)
+ }
+ // The 6 bits are used to specify the prediction method and order as follows:
+ // 000000: Constant prediction method.
+ // 000001: Verbatim prediction method.
+ // 00001x: reserved.
+ // 0001xx: reserved.
+ // 001xxx:
+ // if (xxx <= 4)
+ // Fixed prediction method; xxx=order
+ // else
+ // reserved.
+ // 01xxxx: reserved.
+ // 1xxxxx: FIR prediction method; xxxxx=order-1
+ switch {
+ case x < 1:
+ // 000000: Constant prediction method.
+ subframe.Pred = PredConstant
+ case x < 2:
+ // 000001: Verbatim prediction method.
+ subframe.Pred = PredVerbatim
+ case x < 8:
+ // 00001x: reserved.
+ // 0001xx: reserved.
+ return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
+ case x < 16:
+ // 001xxx:
+ // if (xxx <= 4)
+ // Fixed prediction method; xxx=order
+ // else
+ // reserved.
+ order := int(x & 0x07)
+ if order > 4 {
+ return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
+ }
+ subframe.Pred = PredFixed
+ subframe.Order = order
+ case x < 32:
+ // 01xxxx: reserved.
+ return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
+ default:
+ // 1xxxxx: FIR prediction method; xxxxx=order-1
+ subframe.Pred = PredFIR
+ subframe.Order = int(x&0x1F) + 1
+ }
+
+ // 1 bit: hasWastedBits.
+ x, err = br.Read(1)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x != 0 {
+ // k wasted bits-per-sample in source subblock, k-1 follows, unary coded;
+ // e.g. k=3 => 001 follows, k=7 => 0000001 follows.
+ x, err = br.ReadUnary()
+ if err != nil {
+ return unexpected(err)
+ }
+ subframe.Wasted = uint(x) + 1
+ }
+
+ return nil
+}
+
+// Pred specifies the prediction method used to encode the audio samples of a
+// subframe.
+type Pred uint8
+
+// Prediction methods.
+const (
+ // PredConstant specifies that the subframe contains a constant sound. The
+ // audio samples are encoded using run-length encoding. Since every audio
+ // sample has the same constant value, a single unencoded audio sample is
+ // stored in practice. It is replicated a number of times, as specified by
+ // BlockSize in the frame header.
+ PredConstant Pred = iota
+ // PredVerbatim specifies that the subframe contains unencoded audio samples.
+ // Random sound is often stored verbatim, since no prediction method can
+ // compress it sufficiently.
+ PredVerbatim
+ // PredFixed specifies that the subframe contains linear prediction coded
+ // audio samples. The coefficients of the prediction polynomial are selected
+ // from a fixed set, and can represent 0th through fourth-order polynomials.
+ // The prediction order (0 through 4) is stored within the subframe along
+ // with the same number of unencoded warm-up samples, which are used to kick
+ // start the prediction polynomial. The remainder of the subframe stores
+ // encoded residuals (signal errors) which specify the difference between the
+ // predicted and the original audio samples.
+ PredFixed
+ // PredFIR specifies that the subframe contains linear prediction coded audio
+ // samples. The coefficients of the prediction polynomial are stored in the
+ // subframe, and can represent 0th through 32nd-order polynomials. The
+ // prediction order (0 through 32) is stored within the subframe along with
+ // the same number of unencoded warm-up samples, which are used to kick start
+ // the prediction polynomial. The remainder of the subframe stores encoded
+ // residuals (signal errors) which specify the difference between the
+ // predicted and the original audio samples.
+ PredFIR
+)
+
+// signExtend interprets x as a signed n-bit integer value and sign extends it
+// to 32 bits.
+func signExtend(x uint64, n uint) int32 {
+ // x is signed if its most significant bit is set.
+ if x&(1<<(n-1)) != 0 {
+ // Sign extend x.
+ return int32(x | ^uint64(0)<> uint(shift))
+ }
+ return nil
+}
diff --git a/go.mod b/go.mod
new file mode 100755
index 0000000..2986412
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,8 @@
+module github.com/mewkiz/flac
+
+go 1.14
+
+require (
+ github.com/icza/bitio v1.1.0
+ github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14
+)
diff --git a/go.sum b/go.sum
new file mode 100755
index 0000000..3653f5a
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,37 @@
+github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
+github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0=
+github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
+github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
+github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
+github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
+github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14 h1:tnAPMExbRERsyEYkmR1YjhTgDM0iqyiBYf8ojRXxdbA=
+github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14/go.mod h1:QYCFBiH5q6XTHEbWhR0uhR3M9qNPoD2CSQzr0g75kE4=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/bits/reader.go b/internal/bits/reader.go
new file mode 100755
index 0000000..85027bc
--- /dev/null
+++ b/internal/bits/reader.go
@@ -0,0 +1,84 @@
+// Package bits provides bit access operations and binary decoding algorithms.
+package bits
+
+import (
+ "fmt"
+ "io"
+)
+
+// A Reader handles bit reading operations. It buffers bits up to the next byte
+// boundary.
+type Reader struct {
+ // Underlying reader.
+ r io.Reader
+ // Temporary read buffer.
+ buf [8]uint8
+ // Between 0 and 7 buffered bits since previous read operations.
+ x uint8
+ // The number of buffered bits in x.
+ n uint
+}
+
+// NewReader returns a new Reader that reads bits from r.
+func NewReader(r io.Reader) *Reader {
+ return &Reader{r: r}
+}
+
+// Read reads and returns the next n bits, at most 64. It buffers bits up to the
+// next byte boundary.
+func (br *Reader) Read(n uint) (x uint64, err error) {
+ if n == 0 {
+ return 0, nil
+ }
+ if n > 64 {
+ return 0, fmt.Errorf("bit.Reader.Read: invalid number of bits; n (%d) exceeds 64", n)
+ }
+
+ // Read buffered bits.
+ if br.n > 0 {
+ switch {
+ case br.n == n:
+ br.n = 0
+ return uint64(br.x), nil
+ case br.n > n:
+ br.n -= n
+ mask := ^uint8(0) << br.n
+ x = uint64(br.x&mask) >> br.n
+ br.x &^= mask
+ return x, nil
+ }
+ n -= br.n
+ x = uint64(br.x)
+ br.n = 0
+ }
+
+ // Fill the temporary buffer.
+ bytes := n / 8
+ bits := n % 8
+ if bits > 0 {
+ bytes++
+ }
+ _, err = io.ReadFull(br.r, br.buf[:bytes])
+ if err != nil {
+ return 0, err
+ }
+
+ // Read bits from the temporary buffer.
+ for _, b := range br.buf[:bytes-1] {
+ x <<= 8
+ x |= uint64(b)
+ }
+ b := br.buf[bytes-1]
+ if bits > 0 {
+ x <<= bits
+ br.n = 8 - bits
+ mask := ^uint8(0) << br.n
+ x |= uint64(b&mask) >> br.n
+ br.x = b & ^mask
+ } else {
+ x <<= 8
+ x |= uint64(b)
+ }
+
+ return x, nil
+}
diff --git a/internal/bits/reader_test.go b/internal/bits/reader_test.go
new file mode 100755
index 0000000..5acaede
--- /dev/null
+++ b/internal/bits/reader_test.go
@@ -0,0 +1,688 @@
+// © 2013 the Bits Authors under the MIT license. See AUTHORS for the list of authors.
+//
+// Some benchmark functions in this file were adapted from github.com/bamiaux/iobit
+// which came with the following copyright notice:
+// Copyright 2013 Benoît Amiaux. All rights reserved.
+
+package bits
+
+import (
+ "bytes"
+ "io"
+ "math/rand"
+ "testing"
+)
+
+func TestRead(t *testing.T) {
+ tests := []struct {
+ data []byte
+ ns []uint
+ vals []uint64
+ }{
+ // 11111111
+ {[]byte{0xFF}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 1, 1, 1, 1, 1, 1, 1}},
+ {[]byte{0xFF}, []uint{2, 2, 2, 2}, []uint64{0x3, 0x3, 0x3, 0x3}},
+ {[]byte{0xFF}, []uint{3, 3, 2}, []uint64{0x7, 0x7, 0x3}},
+ {[]byte{0xFF}, []uint{4, 4}, []uint64{0xF, 0xF}},
+ {[]byte{0xFF}, []uint{5, 3}, []uint64{0x1F, 0x7}},
+ {[]byte{0xFF}, []uint{6, 2}, []uint64{0x3F, 0x3}},
+ {[]byte{0xFF}, []uint{7, 1}, []uint64{0x7F, 0x1}},
+ {[]byte{0xFF}, []uint{8}, []uint64{0xFF}},
+
+ // 10101010
+ {[]byte{0xAA}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 0, 1, 0, 1, 0, 1, 0}},
+ {[]byte{0xAA}, []uint{2, 2, 2, 2}, []uint64{0x2, 0x2, 0x2, 0x2}},
+ {[]byte{0xAA}, []uint{3, 3, 2}, []uint64{0x5, 0x2, 0x2}},
+ {[]byte{0xAA}, []uint{4, 4}, []uint64{0xA, 0xA}},
+ {[]byte{0xAA}, []uint{5, 3}, []uint64{0x15, 0x2}},
+ {[]byte{0xAA}, []uint{6, 2}, []uint64{0x2A, 0x2}},
+ {[]byte{0xAA}, []uint{7, 1}, []uint64{0x55, 0x0}},
+ {[]byte{0xAA}, []uint{8}, []uint64{0xAA}},
+
+ {[]byte{0xAA}, []uint{0}, []uint64{0}},
+
+ // orig: 101010101010101010101010101010101010101010101010101010101010101010101010
+ // 6 bits: 101010 (0x2A)
+ // 64 bits: 1010101010101010101010101010101010101010101010101010101010101010 (0xAAAAAAAAAAAAAAAA)
+ // 2 bit: 10 (0x2)
+ {[]byte{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, []uint{6, 64, 2}, []uint64{0x2A, 0xAAAAAAAAAAAAAAAA, 0x2}},
+
+ // 01 1011011 011011 0
+ {[]byte{0x6D, 0xB6}, []uint{2, 7, 6, 1}, []uint64{0x1, 0x5B, 0x1B, 0x0}},
+
+ {
+ []byte{0x21, 0x0F, 0xC7, 0xBB, 0x81, 0x86, 0x39, 0xAC, 0x48, 0xA4, 0xC6, 0xAF, 0xA2, 0xF1, 0x58, 0x1A, 0x8B, 0x95, 0x25, 0xE2, 0x0F, 0xDA, 0x68, 0x92, 0x7F, 0x2B, 0x2F, 0xF8, 0x36, 0xF7, 0x35, 0x78, 0xDB, 0x0F, 0xA5, 0x4C, 0x29, 0xF7, 0xFD, 0x92, 0x8D, 0x92, 0xCA, 0x43, 0xF1, 0x93, 0xDE, 0xE4, 0x7F, 0x59, 0x15, 0x49, 0xF5, 0x97, 0xA8, 0x11, 0xC8, 0xFA, 0x67, 0xAB, 0x03, 0x1E, 0xBD, 0x9C, 0x6A, 0xA4, 0xE9, 0x82, 0x9F, 0x22, 0x4B, 0xE8, 0xEA, 0xF6, 0x67, 0x26, 0xC9, 0x07, 0x7C, 0xB4, 0x1F, 0x79, 0x01, 0x9D, 0x89, 0x2B, 0xE9, 0x93, 0x03, 0xB2, 0xBE, 0x58, 0x82, 0xF3, 0x24, 0x07, 0x58, 0xA3, 0x8D, 0x7E},
+ []uint{2, 40, 28, 62, 8, 59, 51, 54, 63, 49, 11, 42, 64, 7, 41, 2, 4, 58, 24, 55, 63, 13},
+ []uint64{0x00, 0x843F1EEE06, 0x18E6B12, 0xA4C6AFA2F1581A8, 0xB9, 0x292F107ED34493F, 0x4ACBFE0DBDCD5, 0x38DB0FA54C29F7, 0x7EC946C96521F8C9, 0x1DEE47F591549, 0x7AC, 0x2F502391F4C, 0xF56063D7B38D549D, 0x18, 0x53E4497D1D, 0x01, 0x07, 0x2CCE4D920EF9683, 0xEF2033, 0x5892BE99303B2B, 0x72C41799203AC51C, 0xD7E},
+ },
+ {
+ []byte{0x0D, 0xAF, 0x62, 0xD6, 0x5D, 0xCE, 0x5B, 0xA5, 0x24, 0xF7, 0x35, 0x8E, 0xFB, 0xB5, 0xB8, 0x32, 0x20, 0xCF, 0x58, 0x63, 0x6C, 0xBC, 0x40, 0xCF, 0xAC, 0x9A, 0xEB, 0x3C, 0xC8, 0x47, 0xBC, 0xDC, 0xF1, 0x0F, 0x71, 0x7A, 0xA2, 0x62, 0x77, 0xFF, 0x0A, 0x3A, 0x0E, 0xC7, 0x3E, 0x10, 0xFF, 0x40, 0x8E, 0xCE, 0x87, 0x28, 0xF8, 0x4A, 0xE1, 0xAF, 0x7B, 0xBF, 0x86, 0xE9, 0x94, 0x6F, 0xB0, 0x8F, 0xB6, 0x58, 0x97, 0x5A, 0xB5, 0x52, 0x9D, 0x70, 0x40, 0x74, 0xAF, 0x4A, 0xC8, 0xC0, 0xF5, 0xA4, 0x6F, 0x09, 0x6E, 0xE8, 0x47, 0x7A, 0x77, 0x54, 0x30, 0x03, 0x8F, 0xC0, 0x0E, 0xAC, 0x03, 0xAF, 0x4D, 0xDC, 0xD3, 0x25},
+ []uint{62, 44, 50, 50, 7, 53, 11, 9, 57, 37, 35, 54, 30, 45, 5, 8, 59, 9, 13, 48, 62, 46, 6},
+ []uint64{0x36BD8B5977396E9, 0x493DCD63BEE, 0x35B83220CF586, 0xDB2F1033EB26, 0x5D, 0xCF3211EF373C4, 0x1EE, 0x5E, 0x151313BFF851D07, 0xC73E10FF4, 0x47674394, 0x1F095C35EF77F0, 0x374CA37D, 0x108FB658975A, 0x16, 0xAA, 0x29D704074AF4AC8, 0x181, 0x1D69, 0x1BC25BBA11DE, 0x2775430038FC00EA, 0x300EBD37734C, 0x25},
+ },
+ {
+ []byte{0x08, 0x0F, 0x1D, 0xFD, 0xC9, 0xC4, 0xAD, 0x25, 0x6F, 0x47, 0x56, 0x20, 0x46, 0xFC, 0x40, 0x54, 0xF5, 0x9B, 0x5B, 0xE5, 0x46, 0x5E, 0x75, 0xE6, 0xE0, 0xAA, 0x60, 0xC8, 0xEB, 0x2E, 0xE5, 0xD4, 0xCD, 0x26, 0x50, 0xA8, 0x1C, 0xCE, 0xE3, 0x55, 0x07, 0xA1, 0x1A, 0x37, 0x90, 0x71, 0xC7, 0x51, 0xF7, 0x1F, 0xDF, 0x0D, 0xFE, 0xB3, 0xFB, 0xC8, 0xF0, 0x08, 0x25, 0xE6, 0x4C, 0x27, 0x62, 0xFA, 0xC9, 0xFE, 0x63, 0xE2, 0x42, 0x03, 0x7A, 0x8B, 0xC4, 0x03, 0x69, 0x6E, 0x07, 0x33, 0x42, 0x37, 0x10, 0x4C, 0x5E, 0xC5, 0x64, 0x2C, 0xA3, 0xC1, 0xC2, 0x55, 0x0A, 0x87, 0x16, 0xA9, 0x28, 0xE7, 0xCD, 0xBA, 0xEA, 0xC9},
+ []uint{64, 38, 1, 25, 10, 6, 13, 38, 27, 13, 48, 53, 3, 30, 60, 39, 32, 34, 5, 1, 56, 26, 47, 21, 43, 32, 35},
+ []uint64{0x80F1DFDC9C4AD25, 0x1BD1D58811, 0x01, 0xFC4054, 0x3D6, 0x1B, 0xB7C, 0x2A32F3AF37, 0x2A9832, 0x759, 0x772EA6693285, 0x81CCEE35507A1, 0x00, 0x346F20E3, 0x8EA3EE3FBE1BFD6, 0x3FBC8F0082, 0x5E64C276, 0xBEB27F98, 0x1F, 0x00, 0x242037A8BC4036, 0x25B81CC, 0x6846E2098BD8, 0x1590B2, 0x478384AA150, 0xE2D5251C, 0x7CDBAEAC9},
+ },
+ {
+ []byte{0x49, 0x2C, 0x95, 0x56, 0xD7, 0x40, 0x88, 0xA9, 0x13, 0x2E, 0x4A, 0x5C, 0x13, 0xCC, 0x15, 0x9A, 0xA6, 0xEB, 0x4A, 0x0E, 0x9B, 0x96, 0x3C, 0xAD, 0xD1, 0x6E, 0x9C, 0x2D, 0xBA, 0xFD, 0xCE, 0x26, 0xC7, 0x18, 0xBC, 0xDC, 0x0F, 0xA7, 0xD4, 0xAD, 0x15, 0x5E, 0xEB, 0xCC, 0xB9, 0x46, 0x71, 0xE3, 0xDD, 0xFB, 0x4B, 0x99, 0x7D, 0x5B, 0x3F, 0xE4, 0xA4, 0x8B, 0x59, 0x8E, 0x7D, 0x89, 0xDF, 0xFF, 0x84, 0x0D, 0xAE, 0xCA, 0xA8, 0x9B, 0x8E, 0xF2, 0x31, 0xF6, 0xF2, 0x7E, 0x13, 0xDA, 0xEB, 0xE2, 0xED, 0xCD, 0xED, 0x9F, 0x38, 0xC6, 0x9E, 0x7F, 0x7A, 0xA1, 0x83, 0x4E, 0xDA, 0x01, 0xE3, 0x35, 0x41, 0x20, 0x10, 0xA6},
+ []uint{18, 61, 54, 29, 43, 60, 15, 25, 42, 47, 8, 6, 7, 2, 37, 8, 13, 24, 49, 16, 22, 19, 36, 17, 43, 27, 9, 5, 36, 22},
+ []uint64{0x124B2, 0xAAB6BA044548997, 0x94B827982B354, 0x1BAD283A, 0x372C795BA2D, 0xD385B75FB9C4D8E, 0x18BC, 0x1B81F4F, 0x2A568AAF75E, 0x32E519C78F77, 0xED, 0x0B, 0x4C, 0x02, 0x1F56CFF929, 0x22, 0x1ACC, 0x73EC4E, 0x1FFF840DAECAA, 0x89B8, 0x3BC8C7, 0x6DE4F, 0xC27B5D7C5, 0x1B737, 0x5B3E718D3CF, 0x77AA183, 0x9D, 0x16, 0x8078CD504, 0x2010A6},
+ },
+ {
+ []byte{0x7B, 0x22, 0xD1, 0x15, 0x7D, 0x2A, 0x8F, 0x5E, 0x35, 0x8E, 0xFD, 0x26, 0x3D, 0x98, 0xF0, 0x10, 0x18, 0xD7, 0x1E, 0xDC, 0x1D, 0x54, 0x3A, 0x4D, 0xF3, 0xED, 0xDB, 0x19, 0x46, 0xF8, 0x5B, 0xF3, 0xE5, 0x2C, 0x4B, 0xB6, 0x80, 0x08, 0x4D, 0x27, 0x71, 0x58, 0xAA, 0x81, 0x28, 0x1C, 0x8A, 0xB5, 0x47, 0x6A, 0x84, 0x1B, 0xF2, 0x23, 0xC1, 0xC0, 0x6E, 0x51, 0xF9, 0xB5, 0x19, 0x80, 0xCD, 0xF8, 0x06, 0x6B, 0x31, 0xF6, 0x23, 0x84, 0x1C, 0xB6, 0xBF, 0xEA, 0x59, 0x9B, 0xD8, 0x4F, 0x84, 0x04, 0xDB, 0x4B, 0x71, 0xE4, 0xAE, 0xF2, 0xD6, 0xE9, 0x2A, 0x16, 0x42, 0x9E, 0x0C, 0xFC, 0xA6, 0x84, 0x79, 0xC8, 0x2A, 0x23},
+ []uint{52, 58, 42, 30, 54, 55, 26, 15, 18, 43, 47, 34, 58, 3, 15, 17, 48, 8, 50, 49, 37, 18, 23},
+ []uint64{0x7B22D1157D2A8, 0x3D78D63BF498F66, 0xF01018D71E, 0x3707550E, 0x24DF3EDDB1946F, 0x42DF9F29625DB4, 0x109A4, 0x7715, 0x22AA0, 0x25039156A8E, 0x6A841BF223C1, 0x301B947E6, 0x351980CDF8066B3, 0x00, 0x7D88, 0x1C20E, 0x5B5FF52CCDEC, 0x27, 0x30809B696E3C9, 0xBBCB5BA4A859, 0x14F067E53, 0x108F3, 0x482A23},
+ },
+ {
+ []byte{0x0B, 0xBD, 0x5B, 0x49, 0x1C, 0x14, 0x1C, 0xE6, 0x96, 0x97, 0x97, 0x3C, 0x76, 0x70, 0xF4, 0x3E, 0xBA, 0x37, 0x88, 0xB2, 0x46, 0xBF, 0x22, 0xE9, 0xA2, 0x84, 0x7A, 0x3D, 0xF2, 0x12, 0xC9, 0xB5, 0x28, 0x15, 0x0A, 0x31, 0x4E, 0xFC, 0x13, 0x09, 0x02, 0x41, 0x3F, 0xCC, 0x8E, 0x0B, 0x06, 0xD1, 0xA3, 0x80, 0x6E, 0x48, 0x12, 0x00, 0xA7, 0xD2, 0x77, 0xCD, 0x9D, 0xB5, 0x91, 0x13, 0x0A, 0x45, 0xBB, 0xE3, 0xFA, 0x0F, 0xC7, 0x8F, 0x4F, 0x4C, 0x3C, 0xB3, 0xC1, 0xD7, 0xC8, 0x92, 0xB1, 0x32, 0x0B, 0x07, 0x21, 0x27, 0x60, 0x0A, 0xF5, 0x44, 0xDB, 0x90, 0x8C, 0x62, 0xBB, 0x20, 0xB1, 0x84, 0x3B, 0xDB, 0xAF, 0xDB},
+ []uint{5, 4, 44, 10, 7, 54, 2, 22, 24, 49, 32, 52, 63, 57, 25, 5, 61, 22, 9, 25, 51, 12, 14, 1, 23, 57, 16, 40, 14},
+ []uint64{0x01, 0x07, 0x7AB69238283, 0x273, 0x25, 0x297973C7670F43, 0x03, 0x2BA378, 0x8B246B, 0x1E45D34508F47, 0xBE425936, 0xA502A14629DF8, 0x130902413FCC8E0B, 0xDA34700DC9024, 0x29F49, 0x1B, 0x1CD9DB591130A45B, 0x2F8FE8, 0x7E, 0x78F4F4, 0x61E59E0EBE449, 0x589, 0x2416, 0x00, 0xE424E, 0x1802BD5136E4231, 0x8AEC, 0x82C610EF6E, 0x2FDB},
+ },
+ {
+ []byte{0x48, 0xB3, 0x01, 0xCE, 0x08, 0x20, 0xE4, 0xBD, 0x27, 0x21, 0x0A, 0x77, 0x34, 0x5A, 0x50, 0x74, 0xD5, 0x56, 0xCB, 0xE2, 0xCB, 0x7A, 0x63, 0x5F, 0xE3, 0x04, 0x52, 0x87, 0xA8, 0x16, 0x3D, 0x78, 0xE5, 0xC3, 0x82, 0x84, 0x80, 0xC9, 0x67, 0xD4, 0x34, 0xB4, 0xAF, 0xEF, 0x9F, 0x91, 0x5E, 0x1B, 0x8D, 0xF5, 0x43, 0x24, 0xB4, 0xDA, 0xD0, 0xBA, 0xC0, 0xEE, 0xF1, 0x94, 0xA1, 0xE8, 0xAC, 0xDB, 0x84, 0xB8, 0xDC, 0x99, 0x62, 0x4B, 0x19, 0xD1, 0xF8, 0xC5, 0x48, 0x7E, 0xEB, 0x9F, 0x82, 0xFF, 0xE9, 0xA4, 0x88, 0x86, 0x5C, 0x28, 0x60, 0x0F, 0xA3, 0xA7, 0x0B, 0x97, 0xFE, 0x4C, 0x99, 0x17, 0x08, 0xB5, 0x58, 0x94},
+ []uint{34, 25, 22, 55, 18, 20, 35, 30, 1, 12, 30, 64, 32, 33, 51, 3, 32, 32, 15, 10, 25, 26, 26, 20, 62, 63, 24},
+ []uint64{0x122CC0738, 0x410725, 0x3A4E42, 0xA77345A5074D5, 0x15B2F, 0x8B2DE, 0x4C6BFC608, 0x2943D40B, 0x00, 0x3D7, 0x23970E0A, 0x1203259F50D2D2BF, 0xBE7E4578, 0xDC6FAA19, 0x12D36B42EB03B, 0x05, 0xE32943D1, 0x59B70971, 0x5C99, 0x189, 0x58CE8F, 0x318A90F, 0x375CFC1, 0x7FF4D, 0x9110CB850C01F47, 0x270B97FE4C991708, 0xB55894},
+ },
+ {
+ []byte{0x48, 0x34, 0xA6, 0xF7, 0xD5, 0x71, 0x21, 0x1F, 0x5D, 0x73, 0xC4, 0xCF, 0x93, 0x0B, 0x9C, 0x62, 0xD3, 0xD2, 0x0F, 0x53, 0x68, 0xFC, 0x22, 0x1B, 0x99, 0x91, 0x60, 0x87, 0x45, 0x9C, 0x56, 0x41, 0x66, 0x1C, 0x32, 0x52, 0xB0, 0xAA, 0xA1, 0x65, 0xED, 0x1D, 0x0F, 0x3E, 0x40, 0x5B, 0x80, 0xD1, 0xE8, 0x6B, 0x4C, 0x1A, 0x7E, 0xAD, 0xC2, 0x77, 0x36, 0xA5, 0x02, 0x01, 0x21, 0x98, 0x92, 0x1C, 0x7A, 0xCB, 0x68, 0x3B, 0x03, 0xFC, 0xC9, 0x67, 0xF7, 0x77, 0x65, 0xE7, 0xFA, 0x5E, 0xF9, 0xE5, 0x92, 0x2A, 0x97, 0x7C, 0xAC, 0x82, 0xF5, 0xEE, 0xAD, 0x81, 0xF4, 0xB9, 0xF0, 0xF7, 0xA7, 0x9C, 0x91, 0xC6, 0x51, 0x4D},
+ []uint{61, 55, 35, 55, 14, 6, 37, 60, 46, 25, 52, 62, 27, 23, 3, 27, 39, 19, 31, 2, 6, 52, 7, 48, 8},
+ []uint64{0x90694DEFAAE2423, 0x75D73C4CF930B9, 0x63169E907, 0x54DA3F0886E664, 0x1608, 0x1D, 0x2CE2B20B3, 0xE1929585550B2F, 0x1A3A1E7C80B7, 0x347A1, 0xAD3069FAB709D, 0x336A502012198921, 0x63D65B4, 0xEC0FF, 0x01, 0x4967F77, 0x3B2F3FD2F7, 0x67964, 0x4552EF95, 0x02, 0x10, 0x5EBDD5B03E973, 0x70, 0xF7A79C91C651, 0x4D},
+ },
+ {
+ []byte{0x04, 0x2A, 0xDC, 0xC2, 0x25, 0xBF, 0x31, 0x81, 0x18, 0xE5, 0x6F, 0xAD, 0xE0, 0x60, 0x2C, 0xAC, 0x62, 0xF2, 0xD5, 0x59, 0xB9, 0x26, 0xAE, 0x4D, 0x67, 0x86, 0x7B, 0x23, 0xA2, 0xCB, 0xAC, 0x63, 0x06, 0xB2, 0xE3, 0x2F, 0x73, 0x59, 0x64, 0x79, 0xAC, 0x74, 0x15, 0xF2, 0x51, 0x14, 0xFB, 0x45, 0x06, 0xBB, 0xF0, 0x29, 0x5A, 0xD2, 0x90, 0x6F, 0x24, 0xB9, 0x8F, 0x06, 0x54, 0xAE, 0x56, 0x33, 0x3D, 0x79, 0x92, 0x42, 0x50, 0xCF, 0x16, 0x53, 0xCB, 0xC6, 0x57, 0x45, 0x17, 0xEA, 0x69, 0x40, 0xAC, 0xCB, 0x97, 0x74, 0xA0, 0x8A, 0x79, 0x40, 0xA1, 0x2E, 0x63, 0xCA, 0x61, 0xCD, 0x98, 0x2B, 0xCF, 0x55, 0x3A, 0xCB},
+ []uint{4, 14, 31, 4, 42, 46, 62, 30, 58, 51, 6, 1, 39, 61, 52, 24, 48, 57, 6, 50, 44, 1, 54, 15},
+ []uint64{0x00, 0x10AB, 0x39844B7E, 0x06, 0xC08C72B7D6, 0x3C0C05958C5E, 0x16AACDC935726B3C, 0xCF64745, 0x25D63183597197B, 0x4D6591E6B1D05, 0x1F, 0x00, 0x25114FB450, 0xD77E052B5A520DE, 0x49731E0CA95CA, 0xC667AF, 0x32484A19E2CA, 0xF2F195D145FA9A, 0x14, 0x2B32E5DD2822, 0x9E50284B98F, 0x00, 0x14C39B30579EAA, 0x3ACB},
+ },
+ {
+ []byte{0x8A, 0xCC, 0x20, 0x56, 0x0B, 0x1B, 0x64, 0xA3, 0x37, 0x3A, 0x54, 0xD7, 0x6E, 0x2B, 0x16, 0x8E, 0x92, 0xE5, 0xC1, 0xCA, 0x2B, 0xE8, 0x00, 0x8A, 0x64, 0xBF, 0x5C, 0x3F, 0x3F, 0xF6, 0x3C, 0x11, 0x80, 0x34, 0x84, 0x3E, 0xE4, 0x04, 0x51, 0x7C, 0x54, 0xA0, 0x07, 0x59, 0xD3, 0x2E, 0x19, 0x3E, 0x1E, 0xAE, 0x16, 0x47, 0x2F, 0xF5, 0xF1, 0x19, 0xB6, 0xA1, 0x36, 0x2D, 0xFC, 0x1B, 0x86, 0x13, 0xE0, 0xF4, 0xF9, 0x68, 0x57, 0x9D, 0x1F, 0xDE, 0xE5, 0x12, 0xD1, 0x94, 0x47, 0xD8, 0xE5, 0x2A, 0xAF, 0xCE, 0xE0, 0xB7, 0x98, 0xB2, 0xE1, 0xEE, 0xA5, 0x7A, 0x89, 0xB4, 0x06, 0x8B, 0x59, 0xD6, 0xBF, 0x69, 0x56, 0x4B},
+ []uint{13, 1, 5, 35, 47, 53, 53, 18, 10, 42, 12, 6, 6, 62, 43, 42, 38, 55, 35, 21, 27, 57, 25, 13, 32, 33, 6, 10},
+ []uint64{0x1159, 0x01, 0x01, 0x1582C6D9, 0x1466E74A9AED, 0x18AC5A3A4B9707, 0x515F40045325F, 0x2B87E, 0x1FF, 0x2C782300690, 0x87D, 0x32, 0x00, 0x228BE2A5003ACE99, 0x3864F87AB85, 0x2472FF5F119, 0x2DA84D8B7F, 0x370C27C1E9F2D, 0x579D1FDE, 0x1CA25A, 0x19447D8, 0x1CA555F9DC16F31, 0xCB87BA, 0x12BD, 0x44DA0345, 0x159D6BF69, 0x15, 0x24B},
+ },
+ {
+ []byte{0x47, 0xC2, 0x96, 0xCD, 0x76, 0xCD, 0x5C, 0x93, 0xA4, 0x08, 0xD0, 0x96, 0x39, 0x5C, 0xE1, 0x02, 0x05, 0xBF, 0xD5, 0x7B, 0xF8, 0xD6, 0xCD, 0x5D, 0x30, 0x6E, 0xD2, 0x31, 0x28, 0xEB, 0x5C, 0x3C, 0x4A, 0x95, 0xF1, 0x3F, 0xB6, 0xA8, 0xAD, 0xB8, 0x53, 0xC8, 0xED, 0x3D, 0x9D, 0xB4, 0xC2, 0x2F, 0xE5, 0x79, 0x94, 0x3F, 0x15, 0x38, 0xBE, 0xEB, 0x51, 0x9B, 0xB9, 0x6F, 0x6F, 0xF1, 0x4F, 0xA6, 0x7F, 0xB4, 0xD0, 0x1B, 0xF7, 0x8A, 0xF7, 0xCC, 0xD8, 0x36, 0x17, 0xD4, 0x9A, 0xAE, 0xFF, 0x04, 0x07, 0xAA, 0x86, 0xC6, 0x12, 0x31, 0x77, 0x8A, 0x5B, 0x15, 0x0B, 0xEB, 0x1C, 0xA4, 0xF8, 0xA2, 0x12, 0xD8, 0x81, 0xA2},
+ []uint{16, 21, 34, 33, 40, 35, 26, 3, 34, 6, 45, 11, 45, 44, 6, 14, 7, 32, 11, 16, 35, 16, 48, 43, 63, 14, 13, 34, 35, 13, 7},
+ []uint64{0x47C2, 0x12D9AE, 0x366AE49D2, 0x8D09639, 0x5CE10205BF, 0x6ABDFC6B6, 0x1ABA60D, 0x06, 0x348C4A3AD, 0x1C, 0x78952BE27F6, 0x6A8, 0x15B70A791DA7, 0xB3B69845FCA, 0x3C, 0x3287, 0x71, 0x538BEEB5, 0xCD, 0xDCB7, 0x5BFC53E99, 0xFED3, 0x406FDE2BDF33, 0x306C2FA9355, 0x6FF0407AA86C6123, 0x5DE, 0x52D, 0x22A17D639, 0x24F8A212D, 0x1103, 0x22},
+ },
+ {
+ []byte{0xAD, 0x57, 0x64, 0x74, 0x59, 0x9A, 0x31, 0x7D, 0x46, 0x3A, 0xD3, 0x15, 0xEA, 0xE7, 0x3A, 0xBC, 0xBF, 0xE7, 0x6A, 0x36, 0xF2, 0x99, 0x7A, 0x5F, 0x09, 0xB2, 0x3E, 0xE5, 0xD6, 0x7D, 0x84, 0x7A, 0x62, 0xB3, 0xD8, 0xC3, 0x84, 0x42, 0x40, 0x59, 0xBE, 0x8A, 0x59, 0xC7, 0x35, 0xD7, 0xC9, 0xB2, 0x6F, 0xDD, 0x67, 0x04, 0x3B, 0x20, 0xDC, 0x27, 0x63, 0x82, 0x34, 0x3D, 0xBC, 0xE6, 0x29, 0x45, 0x15, 0x94, 0xC9, 0x0C, 0xFA, 0xCF, 0x0F, 0x35, 0x58, 0x06, 0x12, 0x51, 0x18, 0xE7, 0x42, 0x11, 0x39, 0xB3, 0xB4, 0xDD, 0xFE, 0x3F, 0xD7, 0x54, 0xB0, 0xF3, 0x56, 0x61, 0x7D, 0xC4, 0x09, 0xA2, 0x1E, 0x36, 0xFA, 0xFA},
+ []uint{23, 21, 29, 16, 60, 23, 38, 41, 14, 27, 15, 61, 34, 40, 47, 21, 23, 51, 2, 30, 50, 53, 38, 4, 29, 10},
+ []uint64{0x56ABB2, 0x74599, 0x1462FA8C, 0x75A6, 0x2BD5CE75797FCED, 0x236F29, 0x25E97C26C8, 0x1F72EB3EC23, 0x34C5, 0x33D8C38, 0x2212, 0x59BE8A59C735D7, 0x326C9BF75, 0x9C10EC8370, 0x4EC704687B79, 0x198A51, 0x22B299, 0x10CFACF0F3558, 0x00, 0x6125118, 0x39D0844E6CED3, 0xEFF1FEBAA5879, 0x2ACC2FB881, 0x03, 0x8878DBE, 0x2FA},
+ },
+ {
+ []byte{0xCD, 0x03, 0x06, 0x80, 0x27, 0x9D, 0x7E, 0x06, 0x6D, 0x29, 0x42, 0xAE, 0x44, 0x8D, 0xA3, 0xC9, 0x85, 0x03, 0xF1, 0x4D, 0x48, 0xB6, 0xC7, 0xDF, 0xBF, 0x87, 0x7E, 0x58, 0xB1, 0x92, 0x87, 0x05, 0x06, 0xE1, 0x6E, 0x0D, 0x15, 0x51, 0x99, 0xC5, 0x6C, 0x71, 0xCF, 0xFB, 0x8F, 0xE2, 0xD3, 0xA2, 0x31, 0x90, 0x4F, 0x38, 0x9C, 0x3A, 0xD7, 0x50, 0xD0, 0x75, 0x70, 0x33, 0x8B, 0x62, 0x44, 0x23, 0x9E, 0x6A, 0x8C, 0xE7, 0xB2, 0xCA, 0x84, 0x3C, 0x9F, 0x57, 0x70, 0x51, 0xA5, 0xBE, 0xD4, 0x4A, 0x3A, 0x61, 0xE8, 0x4E, 0x75, 0x25, 0xCD, 0x4E, 0x72, 0x5C, 0x69, 0xB3, 0x5B, 0x74, 0xF2, 0x4B, 0x76, 0x9C, 0x8B, 0xF0},
+ []uint{47, 52, 30, 11, 13, 23, 37, 17, 13, 18, 26, 3, 64, 5, 37, 21, 37, 46, 28, 8, 23, 48, 1, 9, 30, 42, 15, 23, 26, 16, 12, 19},
+ []uint64{0x6681834013CE, 0xBF033694A1572, 0x91B4793, 0x50, 0x7E2, 0x4D48B6, 0x18FBF7F0EF, 0x1962C, 0xC94, 0xE0A0, 0x370B706, 0x04, 0x55466715B1C73FEE, 0x07, 0x1E2D3A2319, 0x9E71, 0x70EB5D434, 0x7570338B624, 0x4239E6A, 0x8C, 0x73D965, 0x421E4FABB828, 0x01, 0x14B, 0x1F6A251D, 0xC3D09CEA4B, 0x4D4E, 0x392E34, 0x366B6E9, 0xE496, 0xED3, 0x48BF0},
+ },
+ {
+ []byte{0x69, 0x4F, 0x3D, 0x68, 0x86, 0x48, 0x1B, 0x9E, 0x94, 0xFF, 0xDE, 0x36, 0xDD, 0xD1, 0xBF, 0x69, 0x48, 0x8D, 0xCF, 0x2C, 0x2A, 0xA0, 0xA2, 0xFF, 0xC9, 0xD9, 0x6A, 0x99, 0x3D, 0x6D, 0xFA, 0x39, 0x79, 0xAC, 0x87, 0xC1, 0xAF, 0xCE, 0x2A, 0xCF, 0x09, 0x84, 0xFD, 0xC1, 0xE6, 0xC4, 0x27, 0x2E, 0x4A, 0x4C, 0x64, 0x0F, 0xBC, 0x81, 0xFA, 0xED, 0xED, 0x23, 0x29, 0x02, 0x6F, 0xF5, 0x81, 0xC5, 0x18, 0x33, 0x08, 0xC8, 0x7F, 0xE0, 0xD0, 0x90, 0xC0, 0x12, 0x77, 0xEE, 0xEB, 0x6A, 0x6C, 0x11, 0x08, 0xA0, 0xBB, 0xF2, 0x94, 0x80, 0xA1, 0x98, 0xBB, 0x44, 0xDC, 0xE4, 0x07, 0x99, 0x1D, 0x54, 0x18, 0x58, 0x14, 0x39},
+ []uint{20, 47, 3, 29, 11, 38, 53, 36, 6, 20, 14, 8, 55, 6, 32, 23, 49, 28, 16, 50, 20, 55, 41, 3, 31, 13, 33, 39, 21},
+ []uint64{0x694F3, 0x6B443240DCF4, 0x05, 0x7FEF1B6, 0x774, 0x1BF69488DC, 0x1E58554145FF93, 0xB2D5327AD, 0x2F, 0xD1CBC, 0x3590, 0xF8, 0x1AFCE2ACF0984F, 0x37, 0x79B109C, 0x5C9498, 0x1903EF207EBB7, 0xB48CA40, 0x9BFD, 0x181C5183308C8, 0x7FE0D, 0x4860093BF775B, 0xA6C1108A0B, 0x05, 0x7CA52028, 0xCC5, 0x1B44DCE40, 0x3CC8EAA0C2, 0x181439},
+ },
+ {
+ []byte{0xAA, 0xE8, 0x77, 0xB9, 0x9B, 0xB1, 0xDF, 0xCD, 0x24, 0x21, 0xCA, 0xFC, 0x15, 0x32, 0xFC, 0x71, 0x41, 0x53, 0x20, 0x3C, 0x9A, 0x26, 0x5E, 0x35, 0x58, 0x6E, 0x97, 0xC3, 0xEE, 0x5A, 0x8F, 0x6C, 0x26, 0x9C, 0xD9, 0xB0, 0x54, 0xCE, 0x57, 0x3D, 0xDC, 0x41, 0x56, 0xE6, 0xBE, 0x7A, 0x20, 0xEF, 0x04, 0xF6, 0x14, 0x4F, 0x21, 0x78, 0x5A, 0x55, 0x66, 0xA1, 0x3D, 0xF8, 0x7D, 0x5C, 0x10, 0x3C, 0x3F, 0x28, 0x4C, 0x05, 0x62, 0x3F, 0xDA, 0xBF, 0x11, 0xA7, 0x02, 0x8E, 0xC8, 0x4F, 0xC2, 0x4A, 0x86, 0xE4, 0xFD, 0xD4, 0xAC, 0x37, 0x10, 0xD7, 0x60, 0x05, 0x97, 0xE0, 0x08, 0xD8, 0xB6, 0xAA, 0x08, 0xC9, 0xD5, 0x1F},
+ []uint{9, 23, 6, 21, 31, 58, 51, 34, 50, 22, 35, 63, 13, 37, 12, 29, 63, 64, 16, 46, 9, 28, 47, 33},
+ []uint64{0x155, 0x6877B9, 0x26, 0x1D8EFE, 0x3490872B, 0x3C1532FC7141532, 0x1E4D132F1AAC, 0xDD2F87DC, 0x2D47B6134E6CD, 0x20A99C, 0x573DDC415, 0x3735F3D1077827B0, 0x144F, 0x42F0B4AAC, 0xD42, 0xF7E1F57, 0x20787E50980AC47, 0xFB57E234E051D909, 0xF849, 0x143727EEA561, 0x171, 0xD76005, 0x4BF0046C5B55, 0x8C9D51F},
+ },
+ {
+ []byte{0x7E, 0x3B, 0x8C, 0x41, 0x5D, 0x41, 0x24, 0xF4, 0x14, 0x8C, 0x75, 0xCB, 0x0D, 0x8E, 0x08, 0xEA, 0xD9, 0xE5, 0x84, 0x3E, 0x54, 0xA0, 0xD9, 0x22, 0xF5, 0xB8, 0x0D, 0xED, 0x3A, 0x7F, 0x93, 0x06, 0xF8, 0xC8, 0x4A, 0x60, 0x15, 0x65, 0x06, 0x43, 0xFF, 0x3A, 0x50, 0xFE, 0xCE, 0xE0, 0x15, 0x1F, 0x03, 0x7F, 0x2B, 0xB1, 0x04, 0x07, 0x9C, 0xCD, 0x9B, 0xEA, 0xCE, 0xC7, 0xAB, 0x96, 0xD5, 0x42, 0x88, 0x93, 0xBB, 0xD0, 0x2B, 0x74, 0x06, 0x68, 0x3E, 0xE2, 0x80, 0xDA, 0x78, 0x10, 0x94, 0x47, 0x3C, 0x7B, 0xA1, 0x8F, 0x27, 0x55, 0xD7, 0x37, 0xA9, 0x5F, 0xDD, 0x1D, 0xE1, 0xF4, 0x03, 0xA8, 0x99, 0xC2, 0xD0, 0x86},
+ []uint{34, 59, 46, 49, 28, 60, 53, 47, 38, 45, 23, 33, 8, 1, 8, 12, 11, 50, 16, 25, 30, 33, 2, 3, 33, 35, 18},
+ []uint64{0x1F8EE3105, 0x3A8249E82918EB9, 0x186C704756CF, 0x5843E54A0D92, 0x2F5B80D, 0xED3A7F9306F8C84, 0x14C02ACA0C87FE, 0x3A50FECEE015, 0x7C0DFCAEC, 0x8203CE66CDF, 0x2B3B1E, 0x15CB6AA14, 0x44, 0x01, 0x3B, 0xBD0, 0x15B, 0x280CD07DC501B, 0x4F02, 0x2511CF, 0x7BA18F2, 0xEABAE6F5, 0x00, 0x05, 0xFEE8EF0F, 0x500EA2670, 0x2D086},
+ },
+ {
+ []byte{0xDD, 0xE8, 0x87, 0xA5, 0xCA, 0xBB, 0xC8, 0x9F, 0x2F, 0xAF, 0x66, 0xE8, 0xB9, 0x48, 0x0D, 0x31, 0xB5, 0x8E, 0xAA, 0x48, 0x6A, 0x74, 0xCB, 0xC5, 0x9E, 0x1C, 0x1D, 0xE5, 0x1D, 0x89, 0x0A, 0x4B, 0x10, 0x12, 0xAA, 0xFB, 0x08, 0x6B, 0x10, 0x62, 0x55, 0x94, 0xA1, 0x38, 0xB0, 0x4D, 0x3F, 0xB1, 0xA8, 0xFC, 0xA2, 0x0E, 0x6C, 0x6B, 0x65, 0x73, 0x2D, 0x61, 0x47, 0x24, 0xB9, 0xBB, 0xA0, 0x4A, 0xF8, 0x05, 0xF4, 0x74, 0x1B, 0x06, 0x99, 0x93, 0x63, 0x4A, 0xF7, 0x9D, 0x43, 0x23, 0x00, 0x30, 0x39, 0x5A, 0x65, 0x8A, 0xA4, 0x13, 0xF1, 0x6A, 0x29, 0xB7, 0x16, 0x24, 0xDD, 0xDB, 0xF7, 0x75, 0x05, 0x94, 0x48, 0x76},
+ []uint{32, 10, 14, 19, 40, 24, 28, 60, 31, 59, 43, 11, 27, 19, 22, 33, 46, 51, 41, 10, 29, 31, 34, 9, 25, 28, 24},
+ []uint64{0xDDE887A5, 0x32A, 0x3BC8, 0x4F97D, 0x7B3745CA40, 0x698DAC, 0x7552435, 0x3A65E2CF0E0EF28, 0x7624292C, 0x202555F610D620C, 0x25594A138B0, 0x269, 0x7EC6A3F, 0x1441C, 0x3635B2, 0x1732D6147, 0x92E6EE812BE, 0xBE8E8360D33, 0x4D8D2BDE75, 0x32, 0x6006072, 0x5A658AA4, 0x4FC5A8A6, 0x1B8, 0x1624DDD, 0xBF77505, 0x944876},
+ },
+ {
+ []byte{0x80, 0x94, 0x8F, 0xFF, 0xAB, 0xB3, 0x58, 0x12, 0x91, 0x7D, 0xEB, 0xBA, 0x4F, 0xF2, 0x01, 0x6B, 0xCD, 0xFF, 0x44, 0xB7, 0xD7, 0xC7, 0x19, 0xAE, 0x12, 0x9A, 0x65, 0x48, 0x18, 0xD7, 0x10, 0x30, 0x2D, 0x72, 0x76, 0xC1, 0x97, 0x4E, 0xC2, 0x91, 0x40, 0x30, 0x92, 0x47, 0x5E, 0xCB, 0xC2, 0x85, 0xBA, 0xF4, 0xEF, 0x47, 0x3D, 0x70, 0x2D, 0x64, 0xD8, 0x63, 0xAD, 0xB2, 0x96, 0xC4, 0xF1, 0x1A, 0x57, 0xB2, 0xAB, 0xF4, 0x6E, 0x1E, 0x4E, 0x4E, 0x93, 0x32, 0xF1, 0x6C, 0x76, 0x1F, 0xA1, 0xAE, 0xD6, 0x5A, 0x27, 0x1D, 0x37, 0xA9, 0x2B, 0x32, 0x4A, 0xF6, 0x29, 0x47, 0xC0, 0x29, 0x69, 0xCE, 0xA9, 0x64, 0x93, 0xBC},
+ []uint{37, 49, 14, 17, 29, 33, 20, 9, 52, 30, 60, 24, 18, 22, 41, 3, 11, 30, 23, 14, 38, 14, 20, 27, 6, 15, 25, 63, 42, 4, 10},
+ []uint64{0x101291FFF5, 0xECD604A45F7A, 0x3BA4, 0x1FE40, 0x5AF37FD, 0x25BEBE38, 0xCD709, 0x9A, 0x654818D710302, 0x35C9DB06, 0x5D3B0A4500C2491, 0xD7B2F0, 0x285BA, 0x3D3BD1, 0x19EB816B26C, 0x01, 0x475, 0x2D94B627, 0x44695E, 0x32AB, 0x3D1B879393, 0x2933, 0x2F16C, 0x3B0FD0D, 0x1D, 0x565A, 0x4E3A6F, 0x292B324AF62947C0, 0xA5A73AA592, 0x04, 0x3BC},
+ },
+ {
+ []byte{0x00, 0xFA, 0x33, 0x12, 0xCB, 0xA1, 0x5D, 0xC3, 0x6C, 0x6A, 0x85, 0xBF, 0xA2, 0x49, 0x3C, 0x04, 0x16, 0xD2, 0xF2, 0x2E, 0xCA, 0x84, 0x20, 0x29, 0x9D, 0x54, 0x0C, 0xE2, 0x4A, 0x7D, 0x26, 0x36, 0x54, 0xC2, 0x7B, 0x72, 0x3D, 0x4A, 0xA6, 0x6E, 0xAD, 0xDE, 0xF7, 0x94, 0x78, 0xF5, 0xB5, 0x7D, 0x24, 0xB2, 0x9C, 0xC4, 0x5E, 0xA5, 0xE2, 0xF6, 0x2D, 0x5C, 0x7D, 0x8D, 0x32, 0x47, 0x4A, 0xC6, 0x51, 0xBA, 0x66, 0x80, 0xA4, 0xF9, 0x22, 0xF0, 0x3E, 0x51, 0x09, 0xAD, 0x1E, 0x26, 0x1E, 0xC5, 0x0C, 0x2A, 0xFA, 0x7A, 0xDC, 0x8A, 0x6F, 0xF2, 0x3C, 0x0A, 0xD4, 0xAB, 0x25, 0x1F, 0xFD, 0x1A, 0xC1, 0x9E, 0x35, 0x8D},
+ []uint{11, 43, 6, 27, 24, 36, 9, 63, 39, 53, 11, 56, 17, 59, 57, 52, 42, 11, 45, 15, 54, 17, 21, 13, 18, 1},
+ []uint64{0x07, 0x68CC4B2E857, 0x1C, 0x1B63542, 0xDFD124, 0x9E020B697, 0x122, 0x765421014CEAA067, 0x929F498D9, 0xA613DB91EA553, 0x1BA, 0xB77BDE51E3D6D5, 0x1E925, 0x4A73117A978BD8B, 0xAE3EC69923A563, 0x28DD3340527C9, 0x5E07CA2135, 0x51E, 0x4C3D8A1855F, 0x27AD, 0x3229BFC8F02B52, 0x15928, 0x1FFD1A, 0x1833, 0x31AC6, 0x01},
+ },
+ {
+ []byte{0x78, 0xF4, 0x61, 0xC2, 0x47, 0x09, 0x4B, 0x98, 0xDD, 0x2A, 0xF5, 0x9F, 0x24, 0x99, 0x71, 0x4A, 0x3E, 0x0E, 0xB0, 0xEF, 0xB0, 0xAA, 0x6C, 0x61, 0xB2, 0xF6, 0x46, 0x0F, 0xB5, 0x94, 0x3E, 0x64, 0x4A, 0x5B, 0x55, 0xF4, 0x16, 0xF0, 0x65, 0xB4, 0x74, 0xD9, 0x3F, 0x07, 0x29, 0x7E, 0x12, 0xBF, 0xF6, 0xC1, 0x39, 0x0B, 0x1E, 0x33, 0xC0, 0x65, 0xEC, 0x68, 0xA2, 0x1E, 0xBE, 0xD1, 0x5A, 0x66, 0xC2, 0xCD, 0xA6, 0xF2, 0x46, 0x39, 0x03, 0x84, 0xE1, 0xF9, 0x72, 0x46, 0xF5, 0x3E, 0xA3, 0x3B, 0x49, 0x47, 0x0D, 0xB2, 0xBA, 0x43, 0x5A, 0x6B, 0x52, 0xF2, 0x01, 0x99, 0x3F, 0xBB, 0x0F, 0xA3, 0x55, 0x95, 0xB3, 0x5E},
+ []uint{22, 44, 17, 40, 32, 4, 31, 20, 14, 57, 50, 57, 3, 10, 24, 59, 58, 18, 40, 51, 19, 25, 33, 55, 17},
+ []uint64{0x1E3D18, 0x7091C252E63, 0xE957, 0xACF924CB8A, 0x51F07587, 0x07, 0x6C2A9B18, 0x6CBD9, 0x60F, 0x16B287CC894B6AB, 0x3A0B7832DA3A6, 0x193F07297E12BFF, 0x03, 0x182, 0x72163C, 0x33C065EC68A21EB, 0x3B45699B0B369BC, 0x24639, 0x384E1F972, 0x237A9F519DA4A, 0x1C36C, 0x15D21AD, 0x6B52F201, 0x4C9FDD87D1AACA, 0x1B35E},
+ },
+ {
+ []byte{0x5D, 0x8E, 0x1E, 0xCA, 0x9E, 0xB2, 0x62, 0x1F, 0xC3, 0x5C, 0xD0, 0x64, 0xC8, 0x63, 0xD9, 0x53, 0x2F, 0x2E, 0x5E, 0x6D, 0x03, 0xC6, 0xB1, 0xFE, 0x3A, 0xAE, 0x99, 0x3C, 0x47, 0x91, 0x34, 0x15, 0x1C, 0x95, 0xE4, 0xD1, 0xD0, 0xC0, 0xE7, 0xFD, 0x66, 0x35, 0x33, 0xC3, 0x03, 0xAA, 0x77, 0xCC, 0x1C, 0x77, 0x92, 0xB9, 0xA2, 0xD7, 0xE4, 0xEA, 0xD1, 0x4A, 0x74, 0xF4, 0x05, 0x4C, 0xCB, 0xBF, 0xEB, 0x98, 0x20, 0x8F, 0x77, 0x4D, 0xAA, 0x13, 0xD6, 0xB1, 0xCF, 0x80, 0x9D, 0x6B, 0xDB, 0x02, 0xA9, 0xA3, 0xD2, 0x0F, 0xCA, 0x4D, 0xDC, 0xC5, 0x58, 0x10, 0x3D, 0x96, 0x82, 0xF1, 0x00, 0x32, 0x6B, 0x25, 0xFC, 0x0E},
+ []uint{39, 44, 24, 38, 3, 27, 12, 58, 22, 28, 54, 20, 35, 30, 27, 46, 41, 35, 44, 19, 1, 20, 41, 8, 36, 48},
+ []uint64{0x2EC70F654F, 0x59310FE1AE6, 0x832643, 0x7B2A65E5C, 0x05, 0x73681E3, 0x58F, 0x3C755D32788F226, 0x20A8E4, 0xAF268E8, 0x181CFFACC6A678, 0x60754, 0x77CC1C779, 0xAE68B5F, 0x49D5A29, 0x13A7A02A665D, 0x1FEB98208F7, 0x3A6D509EB, 0x58E7C04EB5E, 0x6C0AA, 0x00, 0xD1E90, 0xFCA4DDCC55, 0x81, 0x3D9682F1, 0x326B25FC0E},
+ },
+ {
+ []byte{0xB4, 0x6D, 0x53, 0x49, 0xB7, 0x06, 0x34, 0x33, 0x99, 0x26, 0xC8, 0x16, 0x3E, 0x5F, 0x8E, 0x87, 0x26, 0xDE, 0x13, 0xBD, 0xBA, 0xEA, 0x1A, 0x03, 0xCD, 0x2E, 0xAC, 0x7D, 0x79, 0xFA, 0x25, 0x4F, 0xAF, 0x5B, 0xC4, 0xE4, 0x6A, 0x50, 0x33, 0x83, 0xCC, 0xF5, 0x49, 0x3E, 0xCF, 0xAC, 0xAA, 0x94, 0x89, 0x33, 0xB6, 0xC4, 0x77, 0xBF, 0xAF, 0xE6, 0xFA, 0x07, 0x07, 0x5B, 0x8E, 0x6B, 0x8B, 0xFE, 0x1C, 0xE3, 0x20, 0xF3, 0x17, 0x54, 0x3F, 0x38, 0x99, 0xD4, 0xAB, 0x85, 0xE7, 0x7D, 0x47, 0xE3, 0x41, 0x98, 0xE9, 0x5B, 0xF4, 0x38, 0x18, 0xEE, 0x13, 0x64, 0x2E, 0xC3, 0x5F, 0x22, 0x42, 0x41, 0xCB, 0x62, 0x59, 0xBE},
+ []uint{56, 11, 10, 52, 2, 11, 13, 21, 25, 24, 13, 2, 52, 27, 43, 10, 16, 41, 13, 46, 60, 57, 4, 62, 43, 13, 40, 28, 5},
+ []uint64{0xB46D5349B70634, 0x19C, 0x324, 0xD902C7CBF1D0E, 0x01, 0x1B7, 0x109D, 0x1DBAEA, 0x34079A, 0x5D58FA, 0x1E7E, 0x02, 0x254FAF5BC4E46, 0x52819C1, 0x733D524FB3E, 0x2CA, 0xA948, 0x12676D88EF7, 0x1EBF, 0x26FA07075B8E, 0x6B8BFE1CE320F31, 0xEA87E7133A9570, 0x0B, 0x33BEA3F1A0CC74AD, 0x7D0E063B84D, 0x1217, 0x61AF912120, 0xE5B12CD, 0x1E},
+ },
+ {
+ []byte{0x23, 0xFE, 0xE6, 0xE3, 0x2F, 0x43, 0xE0, 0x65, 0xBD, 0xCA, 0xD1, 0xD8, 0x44, 0x1A, 0x37, 0x2C, 0xF8, 0xB3, 0x17, 0x83, 0x0E, 0x12, 0xDB, 0x23, 0x90, 0x83, 0x9C, 0xBF, 0x7D, 0x16, 0x5E, 0x28, 0xCA, 0x6E, 0x86, 0xE0, 0x09, 0x61, 0x71, 0xE5, 0x00, 0x4D, 0xCE, 0xE1, 0x8A, 0xA8, 0xBD, 0xB1, 0xD5, 0xC4, 0xF2, 0xEF, 0x0B, 0xEE, 0x07, 0x6A, 0x12, 0x2F, 0xB1, 0x2B, 0x5D, 0x0B, 0xC4, 0xD3, 0xE0, 0x9A, 0xC6, 0xDC, 0x25, 0x75, 0x87, 0xC8, 0xB2, 0x7B, 0xAE, 0x6A, 0xC8, 0x3C, 0xF9, 0x2A, 0xC6, 0xD7, 0xBD, 0x6D, 0x88, 0x91, 0x82, 0xAB, 0x01, 0xA0, 0x3C, 0x3E, 0xE2, 0x5B, 0x22, 0xB9, 0xF4, 0x40, 0x13, 0x27},
+ []uint{46, 17, 6, 2, 47, 18, 58, 46, 1, 3, 45, 56, 64, 21, 53, 35, 1, 38, 57, 31, 7, 49, 8, 60, 31},
+ []uint64{0x8FFB9B8CBD0, 0x1F032, 0x37, 0x02, 0x72B47611068D, 0x32CF8, 0x2CC5E0C384B6C8E, 0x10839CBF7D16, 0x00, 0x05, 0x1C5194DD0DC0, 0x12C2E3CA009B9D, 0xC315517B63AB89E5, 0x1BC2FB, 0x103B50917D895A, 0x742F134F8, 0x00, 0x1358DB84AE, 0x161F22C9EEB9AB2, 0x79F2558, 0x6D, 0xF7ADB1123055, 0x60, 0x340787DC4B64573, 0x74401327},
+ },
+ {
+ []byte{0xD7, 0x29, 0xE8, 0xD8, 0x9D, 0x5F, 0x04, 0x11, 0x02, 0x6B, 0xDE, 0x9E, 0x4F, 0x4B, 0xF9, 0x97, 0x75, 0x01, 0xB6, 0x49, 0xE5, 0x48, 0xFF, 0x34, 0x2A, 0xE6, 0xCF, 0x5D, 0x85, 0x6D, 0xF8, 0x35, 0x8C, 0xEA, 0x04, 0xB3, 0x10, 0x5B, 0x07, 0x80, 0x3B, 0xD5, 0x69, 0x4E, 0xD2, 0xA5, 0x9F, 0x6A, 0x38, 0x77, 0x58, 0x5C, 0x79, 0xEB, 0x03, 0x30, 0x5C, 0x5D, 0x7D, 0x47, 0xD1, 0xD3, 0xAE, 0xC2, 0xE8, 0xB5, 0x69, 0x35, 0x58, 0xD5, 0xC2, 0x91, 0x80, 0x4E, 0x1B, 0x87, 0x92, 0xB2, 0x60, 0x69, 0x02, 0x6F, 0x47, 0x1B, 0x89, 0x14, 0x7E, 0x4F, 0xE4, 0xF9, 0xF0, 0x4D, 0xBD, 0x76, 0x72, 0x36, 0xF3, 0xD8, 0xB8, 0x4D},
+ []uint{43, 23, 21, 42, 26, 28, 54, 30, 49, 8, 33, 11, 25, 35, 39, 38, 21, 37, 62, 7, 60, 57, 36, 15},
+ []uint64{0x6B94F46C4EA, 0x7C1044, 0x135EF, 0x13C9E97F32E, 0x3A80DB2, 0x4F2A47F, 0x26855CD9EBB0AD, 0x2FC1AC67, 0xA04B3105B078, 0x03, 0x17AAD29DA, 0x2A5, 0x13ED470, 0x77585C79E, 0x581982E2EB, 0x3A8FA3A75D, 0x10BA2D, 0xB49AAC6AE, 0x523009C370F2564, 0x60, 0x69026F471B89147, 0x1C9FC9F3E09B7AE, 0xCE46DE7B1, 0x384D},
+ },
+ {
+ []byte{0x76, 0x2E, 0x87, 0xCE, 0x9D, 0x1C, 0xF7, 0x87, 0xD8, 0x0E, 0xD4, 0x6B, 0x3D, 0x01, 0x84, 0x6C, 0xDE, 0xF7, 0x72, 0xC4, 0xCC, 0xAE, 0xC4, 0xF4, 0x35, 0xBD, 0xDC, 0xA5, 0x69, 0x4F, 0xFF, 0x98, 0x7D, 0x30, 0xBE, 0x40, 0xE7, 0x39, 0xF6, 0xFD, 0x52, 0x19, 0xD9, 0x51, 0xB4, 0x04, 0x22, 0x5C, 0x93, 0x07, 0x7D, 0xB9, 0xF0, 0x5D, 0x53, 0x67, 0x6E, 0xAA, 0xCF, 0x28, 0x16, 0x14, 0x2C, 0x28, 0x5A, 0xB9, 0x20, 0xD3, 0x8C, 0x42, 0xFC, 0x6D, 0xE5, 0x68, 0x47, 0x84, 0xBF, 0x4D, 0x9C, 0x55, 0x62, 0x56, 0x10, 0xAE, 0xFC, 0x1E, 0x91, 0x8B, 0x52, 0x52, 0x49, 0x25, 0x3C, 0x6F, 0xC0, 0x59, 0x59, 0x2D, 0x80, 0x43},
+ []uint{42, 51, 40, 8, 22, 55, 9, 12, 60, 53, 35, 48, 31, 50, 34, 7, 7, 53, 55, 41, 35, 32, 2, 18},
+ []uint64{0x1D8BA1F3A74, 0x39EF0FB01DA8D, 0x67A0308D9B, 0xDE, 0x3B9626, 0x32BB13D0D6F772, 0x12B, 0x4A7, 0xFFCC3E985F20739, 0x19F6FD5219D951, 0x5A02112E4, 0x983BEDCF82EA, 0x4D9DBAAB, 0xF2816142C285, 0x2AE4834E3, 0x08, 0x2F, 0x18DBCAD08F097E, 0x4D9C55625610AE, 0x1F83D2316A4, 0x5249253C6, 0xFC059592, 0x03, 0x18043},
+ },
+ {
+ []byte{0x33, 0xC2, 0xC3, 0xBC, 0x9D, 0x2A, 0x36, 0xB4, 0x92, 0x36, 0x02, 0x93, 0x54, 0xB9, 0x86, 0x32, 0xC1, 0x0C, 0x75, 0xC4, 0x3B, 0xE4, 0x0A, 0x3F, 0xDF, 0x4E, 0xF6, 0x05, 0x4F, 0x30, 0x19, 0xA6, 0xE9, 0xE6, 0x55, 0xAF, 0xE8, 0xC4, 0x3F, 0xFF, 0xE3, 0x40, 0xC1, 0xA2, 0xE1, 0x05, 0xD7, 0x77, 0x82, 0xD5, 0xF9, 0xA6, 0x0F, 0x54, 0xED, 0x96, 0xA0, 0x68, 0xEC, 0xAE, 0x57, 0xE3, 0x6A, 0xD2, 0xCE, 0x18, 0x9A, 0xC2, 0x5E, 0x10, 0x3C, 0x21, 0x5C, 0x38, 0xA9, 0xC4, 0x82, 0x76, 0xF9, 0xA9, 0x9B, 0x33, 0x43, 0x40, 0x61, 0xDD, 0x0D, 0x83, 0x9E, 0xDE, 0x08, 0x4C, 0x13, 0x33, 0x82, 0x6A, 0xF4, 0xAB, 0x61, 0x1C},
+ []uint{28, 60, 58, 5, 41, 56, 29, 27, 38, 2, 28, 51, 3, 63, 33, 57, 36, 61, 22, 1, 62, 26, 13},
+ []uint64{0x33C2C3B, 0xC9D2A36B4923602, 0x24D52E618CB0431, 0x1A, 0x1C43BE40A3F, 0xDF4EF6054F3019, 0x14DD3CCA, 0x5AFE8C4, 0xFFFF8D030, 0x01, 0xA2E105D, 0x3BBC16AFCD307, 0x05, 0x29DB2D40D1D95CAF, 0x18DAB4B38, 0xC4D612F081E10A, 0xE1C54E241, 0x76F9A99B3343406, 0x77436, 0x00, 0x73DBC1098266704, 0x357A55B, 0x11C},
+ },
+ {
+ []byte{0xCB, 0x0A, 0x64, 0xC1, 0xEF, 0xEC, 0x67, 0x09, 0xE1, 0x9A, 0x2A, 0xC2, 0xC5, 0xD9, 0xC7, 0x3D, 0x2A, 0x49, 0x3E, 0xF4, 0x30, 0xC9, 0x47, 0x2E, 0xEC, 0xAA, 0x46, 0xDA, 0x31, 0x62, 0x27, 0x4F, 0xAD, 0x4C, 0x50, 0xCD, 0x83, 0x51, 0x37, 0x09, 0x8B, 0xC7, 0x6D, 0x62, 0xFE, 0xC3, 0xE9, 0x91, 0xE5, 0xE8, 0x4D, 0x11, 0x1B, 0xDE, 0x03, 0x23, 0xAA, 0x1E, 0x65, 0xAD, 0x06, 0x23, 0x28, 0xD2, 0xDF, 0x59, 0x47, 0x52, 0xF2, 0x3F, 0xC7, 0x68, 0x50, 0x20, 0xF3, 0x2A, 0xC0, 0xFB, 0xBB, 0xC0, 0xAD, 0x26, 0xA6, 0x75, 0x19, 0x1B, 0xD8, 0x1F, 0xF9, 0xFD, 0x33, 0x10, 0x2C, 0x15, 0x80, 0xDC, 0xA7, 0xF6, 0xF4, 0x50},
+ []uint{21, 51, 60, 7, 33, 20, 14, 36, 57, 10, 51, 3, 17, 50, 55, 3, 14, 7, 35, 45, 12, 43, 50, 51, 28, 27},
+ []uint64{0x19614C, 0x4C1EFEC6709E1, 0x9A2AC2C5D9C73D2, 0x52, 0x93EF430C, 0x9472E, 0x3B2A, 0x91B68C588, 0x13A7D6A62866C1A, 0x226, 0x7098BC76D62FE, 0x06, 0x3E99, 0x797A134446F7, 0x40647543CCB5A0, 0x06, 0x8CA, 0x1A, 0x2DF594752, 0x1E47F8ED0A04, 0x1E6, 0x2AC0FBBBC0A, 0x349A99D4646F6, 0x3FF3FA662058, 0x2B01B94, 0x7F6F450},
+ },
+ {
+ []byte{0x56, 0x6B, 0xDA, 0x9E, 0xD9, 0x04, 0x9A, 0xE7, 0x5E, 0x85, 0x25, 0x0B, 0x1D, 0xEF, 0xB8, 0x65, 0x6F, 0xFF, 0xE5, 0x6F, 0x02, 0xA8, 0xE2, 0x9B, 0x18, 0xC2, 0x11, 0x8A, 0x7E, 0xB5, 0xDF, 0x72, 0x44, 0x0C, 0xC7, 0x85, 0x43, 0xC5, 0x75, 0x3A, 0x2B, 0x1F, 0xA5, 0x75, 0x66, 0x42, 0x15, 0x03, 0xB3, 0x2F, 0x90, 0xCB, 0x2B, 0x56, 0x8E, 0x2E, 0xB1, 0x98, 0xD0, 0x5D, 0x53, 0x8D, 0x7C, 0xF8, 0x0E, 0x07, 0x98, 0x60, 0x4E, 0x8D, 0x69, 0xF9, 0x2E, 0xD7, 0x9A, 0xE2, 0x4D, 0x37, 0x49, 0xB9, 0x59, 0x5D, 0x2D, 0xC2, 0x7E, 0x50, 0x7B, 0x97, 0x4F, 0x06, 0x2B, 0xBC, 0xCB, 0x10, 0x3E, 0x0E, 0xD3, 0xF8, 0x7E, 0x78},
+ []uint{38, 55, 32, 34, 58, 58, 53, 8, 29, 19, 37, 46, 7, 55, 39, 44, 24, 5, 5, 22, 19, 11, 49, 40, 13},
+ []uint64{0x159AF6A7B6, 0x20935CEBD0A4A1, 0x63BDF70C, 0x2B7FFF2B7, 0x20551C536318423, 0x53F5AEFB922066, 0x78543C5753A2B, 0x1F, 0x14AEACC8, 0x21503, 0x1665F21965, 0x1AB471758CC6, 0x41, 0x3AA71AF9F01C0F, 0x18604E8D69, 0xF92ED79AE24, 0xD3749B, 0x12, 0x16, 0x15D2DC, 0x13F28, 0x1EE, 0xBA78315DE658, 0x81F0769FC3, 0x1E78},
+ },
+ {
+ []byte{0x52, 0xEE, 0x85, 0xDF, 0x00, 0xC1, 0xE3, 0x65, 0x76, 0x46, 0x99, 0x52, 0xDC, 0xA5, 0x26, 0x5C, 0x31, 0x62, 0xEB, 0xC2, 0xCD, 0xC7, 0x27, 0x12, 0xE4, 0xFC, 0xC5, 0x56, 0xB5, 0xDB, 0x87, 0x39, 0x94, 0xFB, 0x3D, 0x31, 0x24, 0xB7, 0x16, 0x4D, 0x6E, 0x51, 0x8E, 0x47, 0x8E, 0xFF, 0xC0, 0x58, 0x09, 0xC3, 0xE7, 0xCC, 0x5C, 0xA8, 0x82, 0x0F, 0xE2, 0x4D, 0xD2, 0x6D, 0xBF, 0x9B, 0x3D, 0x28, 0xD6, 0x65, 0x6D, 0x0A, 0x05, 0x1B, 0xFA, 0x66, 0x9C, 0xF6, 0x15, 0xCE, 0x50, 0xE1, 0x21, 0x90, 0x9B, 0xA0, 0xDE, 0xDB, 0x76, 0x7C, 0xB6, 0x2D, 0x30, 0xEB, 0xCD, 0x74, 0xE5, 0x19, 0x18, 0xC0, 0x7D, 0x43, 0xA3, 0x61},
+ []uint{33, 22, 19, 36, 45, 49, 18, 64, 5, 22, 40, 5, 2, 47, 9, 13, 9, 54, 55, 11, 32, 15, 22, 55, 41, 37, 24, 7, 9},
+ []uint64{0xA5DD0BBE, 0x60F1, 0x595D9, 0x1A654B729, 0x932E18B175E, 0x2CDC72712E4F, 0x33155, 0xAD76E1CE653ECF4C, 0x09, 0x96E2C, 0x9ADCA31C8F, 0x03, 0x02, 0x7FE02C04E1F3, 0x1CC, 0xB95, 0x20, 0x20FE24DD26DBF9, 0x59E946B32B6850, 0x146, 0xFE99A73D, 0x42B9, 0x328709, 0x6426E837B6DD9, 0x1E5B169875E, 0xD74E51918, 0xC07D43, 0x51, 0x161},
+ },
+ {
+ []byte{0xB0, 0x67, 0x0E, 0x66, 0x77, 0x4D, 0x4E, 0xDB, 0xEB, 0xDC, 0x05, 0x3B, 0xAA, 0xBB, 0xE8, 0x71, 0x59, 0xD4, 0x71, 0x53, 0xBE, 0xF4, 0x78, 0x2A, 0xB8, 0x9F, 0x09, 0xBB, 0x18, 0x2D, 0x89, 0xD7, 0xDF, 0x15, 0xB9, 0xD6, 0x6D, 0x90, 0x3F, 0x2B, 0xBF, 0xF7, 0xC7, 0x41, 0x1D, 0xCA, 0xAB, 0x52, 0x41, 0x21, 0x6F, 0xB1, 0xF1, 0x2F, 0xCD, 0xC8, 0x85, 0xC3, 0xD7, 0x80, 0x82, 0xFB, 0x86, 0x14, 0x3E, 0x34, 0x95, 0x3E, 0x82, 0xE2, 0x14, 0x51, 0x93, 0xFE, 0xEE, 0x0A, 0xF2, 0xFE, 0xDE, 0x97, 0xB7, 0xEF, 0x1F, 0x95, 0x5D, 0x8F, 0xE8, 0x59, 0xC9, 0x5E, 0x9B, 0x9D, 0x35, 0x0C, 0x84, 0x54, 0x7D, 0x7D, 0x30, 0x42},
+ []uint{1, 13, 4, 42, 5, 62, 28, 12, 37, 22, 51, 1, 36, 54, 18, 39, 13, 57, 64, 24, 56, 44, 24, 63, 30},
+ []uint64{0x01, 0xC19, 0x0C, 0xE66774D4ED, 0x17, 0x35EE029DD55DF438, 0xACEA38A, 0x9DF, 0xF4782AB89, 0x3C26EC, 0x305B13AFBE2B7, 0x00, 0x759B640FC, 0x2BBFF7C7411DCA, 0x2AD49, 0x242DF63E2, 0xBF3, 0xE442E1EBC0417D, 0xC30A1F1A4A9F4171, 0xA28C9, 0xFF7705797F6F4B, 0xDBF78FCAAEC, 0x7F42CE, 0x257A6E74D4321151, 0x3D7D3042},
+ },
+ {
+ []byte{0xD8, 0x92, 0xDB, 0xF2, 0x33, 0xA4, 0x8B, 0x06, 0xD6, 0xC5, 0xBE, 0x2D, 0x6B, 0x2B, 0x82, 0x33, 0x75, 0xA7, 0xD4, 0x36, 0x2F, 0x46, 0x81, 0xE1, 0xC7, 0xBB, 0xDC, 0xF9, 0x1C, 0x93, 0xF8, 0xEB, 0xFA, 0x14, 0xF3, 0xD2, 0xCB, 0xD7, 0x70, 0x24, 0xAA, 0x92, 0xE5, 0xB3, 0x14, 0x5F, 0x18, 0x14, 0xEC, 0xC3, 0x5B, 0xF0, 0x33, 0xE7, 0xF6, 0xA7, 0x2D, 0x0F, 0xF7, 0x0A, 0x84, 0xD1, 0x87, 0xEF, 0xDD, 0xCD, 0xDC, 0xA8, 0xA1, 0xEF, 0x18, 0x6F, 0xDB, 0x05, 0x79, 0xD6, 0xF9, 0x33, 0x89, 0x9A, 0x57, 0xB7, 0xAC, 0xFE, 0x1C, 0x49, 0xA5, 0x6B, 0x5D, 0x15, 0x19, 0x1F, 0x74, 0x35, 0x87, 0xB3, 0xDD, 0xF6, 0x91, 0x59},
+ []uint{59, 22, 40, 1, 33, 56, 30, 30, 20, 23, 23, 64, 4, 27, 7, 23, 11, 33, 13, 43, 20, 8, 21, 55, 56, 64, 14},
+ []uint64{0x6C496DF919D2458, 0xDAD8B, 0x7C5AD65704, 0x00, 0x19BAD3EA1, 0xB17A340F0E3DDE, 0x39F23927, 0x3C75FD0A, 0x79E96, 0x2F5DC0, 0x495525, 0xCB6628BE3029D986, 0x0B, 0x3F033E7, 0x7B, 0x29CB43, 0x7EE, 0x2A13461F, 0x17EE, 0x73772A287BC, 0x61BF6, 0xC1, 0xBCEB7, 0x64CE26695EDEB3, 0xF8712695AD7454, 0x647DD0D61ECF77DA, 0x1159},
+ },
+ {
+ []byte{0xEE, 0xDC, 0x02, 0xB6, 0x64, 0xD5, 0x98, 0xBA, 0x54, 0x05, 0x83, 0x4E, 0xB1, 0xC6, 0x5E, 0x02, 0x6F, 0x12, 0x3A, 0xC4, 0xD4, 0x99, 0xF8, 0xF4, 0x4E, 0xC5, 0x5F, 0x69, 0xB9, 0xEE, 0xFF, 0xB0, 0x5A, 0x10, 0x69, 0xEF, 0x95, 0x82, 0xA6, 0x51, 0xAC, 0x06, 0x46, 0x6A, 0x69, 0x80, 0x07, 0x5A, 0xDB, 0x0B, 0x58, 0x49, 0xD3, 0x9B, 0xD6, 0x66, 0xFC, 0x14, 0x05, 0x58, 0x46, 0x98, 0x16, 0xC0, 0x3E, 0x50, 0xDB, 0xD7, 0x68, 0xC1, 0xFE, 0x16, 0xA8, 0xE6, 0x80, 0x21, 0xBA, 0xC1, 0x89, 0xB7, 0xD3, 0xCF, 0xDF, 0x3E, 0x5E, 0xB0, 0x76, 0x25, 0xB0, 0xB8, 0x65, 0xA1, 0x57, 0x35, 0x2B, 0x79, 0x35, 0x23, 0x70, 0x7A},
+ []uint{19, 14, 28, 59, 53, 55, 20, 4, 1, 40, 36, 2, 42, 20, 60, 61, 59, 46, 62, 23, 50, 4, 42},
+ []uint64{0x776E0, 0x56C, 0xC9AB317, 0x25405834EB1C65E, 0x4DE247589A93, 0x1F8F44EC55F69B, 0x9EEFF, 0x0B, 0x00, 0xB420D3DF2, 0xB054CA358, 0x00, 0xC8CD4D3000, 0xEB5B6, 0x16B093A737ACCDF, 0x105015611A605B00, 0x7CA1B7AED183FC2, 0x354734010DD6, 0x3136FA79FBE7CBD, 0x307625, 0x2C2E196855CD4, 0x0A, 0x3793523707A},
+ },
+ {
+ []byte{0x26, 0x44, 0x9D, 0xFF, 0x6D, 0x96, 0x22, 0x0A, 0xD1, 0xF2, 0xE7, 0x81, 0xD8, 0xEC, 0x90, 0xFD, 0x74, 0x52, 0x63, 0x4A, 0x3C, 0x34, 0xDB, 0x1A, 0xA8, 0xDF, 0xA5, 0x62, 0x34, 0x57, 0x32, 0x2C, 0x53, 0xEC, 0xDF, 0x03, 0xFC, 0xE0, 0x86, 0x03, 0x24, 0xCD, 0x44, 0x36, 0xDF, 0xE2, 0x2F, 0x55, 0x25, 0xD6, 0x27, 0xF3, 0x2E, 0xDB, 0x38, 0x31, 0x5D, 0xAC, 0x2C, 0x28, 0x05, 0x33, 0xA2, 0xFB, 0x0D, 0x7C, 0x02, 0x1B, 0x8A, 0xD4, 0xDF, 0xFC, 0x02, 0x69, 0xC4, 0x2C, 0x65, 0x6F, 0x8C, 0xA4, 0x2F, 0x19, 0x04, 0xBE, 0xC5, 0x0F, 0x8C, 0xF0, 0xB1, 0x8A, 0x2E, 0x58, 0x96, 0xC3, 0x87, 0x1F, 0x89, 0x4F, 0xA9, 0x44},
+ []uint{37, 50, 48, 42, 39, 50, 30, 29, 11, 10, 17, 20, 29, 52, 50, 17, 27, 47, 16, 16, 25, 61, 28, 8, 29, 12},
+ []uint64{0x4C893BFED, 0x2CB110568F973, 0xC0EC76487EBA, 0xA4C6947869, 0x5B1AA8DFA5, 0x188D15CC8B14F, 0x2CDF03FC, 0x1C10C064, 0x4CD, 0x110, 0x1B6FF, 0x117AA, 0x125D627F, 0x32EDB38315DAC, 0xB0A014CE8BEC, 0x6BE0, 0x86E2B5, 0x1BFF804D3885, 0x8CAD, 0xF194, 0x10BC641, 0x5F6287C67858C51, 0x72C4B61, 0xC3, 0x11F894FA, 0x944},
+ },
+ {
+ []byte{0x93, 0xC5, 0x74, 0xE2, 0x73, 0x08, 0xB2, 0xDD, 0xB8, 0xD7, 0xD5, 0xC3, 0x88, 0x2F, 0x98, 0xA2, 0xB8, 0x42, 0x98, 0xE2, 0xFD, 0xC6, 0x7F, 0x6C, 0x47, 0xE6, 0xC5, 0x9D, 0x30, 0x31, 0x40, 0x3C, 0x63, 0xE7, 0xD1, 0x20, 0x1E, 0x85, 0xF9, 0x40, 0x98, 0xE8, 0x9F, 0x31, 0xDF, 0x9E, 0x14, 0xEE, 0xB5, 0x62, 0x56, 0x7F, 0x88, 0x3F, 0xE1, 0xD1, 0xEB, 0xAC, 0x09, 0xCD, 0x71, 0xF8, 0x23, 0x07, 0xDA, 0x37, 0x32, 0x37, 0xDE, 0x65, 0x21, 0x72, 0x9B, 0x89, 0x9B, 0xEC, 0x35, 0xBC, 0x6B, 0xB8, 0x20, 0x00, 0xF6, 0xA9, 0x06, 0xDC, 0xAC, 0xE8, 0xC3, 0x52, 0x89, 0x20, 0x74, 0xC9, 0xB3, 0xCC, 0x72, 0x45, 0x0E, 0x76},
+ []uint{49, 42, 47, 16, 27, 33, 16, 39, 45, 23, 47, 52, 64, 20, 17, 63, 30, 50, 23, 54, 31, 12},
+ []uint64{0x1278AE9C4E611, 0x196EDC6BEAE, 0xE20BE628AE1, 0xA63, 0x45FB8CF, 0x1DB11F9B1, 0x674C, 0x628078C7C, 0x1F44807A17E5, 0x131D1, 0x1F31DF9E14EE, 0xB562567F883FE, 0x1D1EBAC09CD71F82, 0x307DA, 0x6E64, 0x37DE6521729B899B, 0x3B0D6F1A, 0x3B82000F6A906, 0x6E5674, 0x186A51240E9936, 0x3CC72450, 0xE76},
+ },
+ {
+ []byte{0xCA, 0x4E, 0x83, 0x60, 0x1A, 0xEF, 0xAC, 0x61, 0x4C, 0x22, 0x4A, 0xE3, 0xFC, 0xEF, 0x32, 0x2A, 0xDB, 0x52, 0x73, 0xC3, 0xEB, 0xA6, 0xF0, 0xAE, 0x35, 0x1D, 0x0C, 0xDE, 0x1D, 0x38, 0x41, 0x75, 0x4B, 0xF3, 0x62, 0x98, 0x73, 0x07, 0xB9, 0x58, 0x83, 0x38, 0x29, 0xE3, 0xCD, 0x38, 0xBA, 0xF0, 0x59, 0xDC, 0x74, 0xE4, 0xE4, 0x17, 0x6C, 0x83, 0xBF, 0x52, 0xDB, 0xEA, 0xF5, 0xFA, 0xBF, 0x1D, 0xBA, 0x13, 0xED, 0xDA, 0x93, 0x6E, 0xCB, 0x89, 0x1E, 0x83, 0x72, 0xC5, 0x28, 0x3A, 0x5F, 0x8D, 0xAF, 0xDB, 0xDD, 0x6E, 0xA9, 0xD2, 0x76, 0x4B, 0x7F, 0x4A, 0xD8, 0x0E, 0xBF, 0xE0, 0xC6, 0x5F, 0xA0, 0x77, 0x7A, 0x2B},
+ []uint{57, 31, 47, 37, 29, 27, 49, 3, 52, 31, 34, 41, 35, 37, 47, 59, 31, 46, 10, 7, 14, 54, 22},
+ []uint64{0x1949D06C035DF58, 0x614C224A, 0x71FE7799156D, 0x15273C3EBA, 0xDE15C6A, 0x1D0CDE1, 0x1A7082EA97E6C, 0x02, 0x987307B958833, 0x414F1E69, 0x3175E0B3B, 0x11D393905DB, 0x1077EA5B7, 0x1ABD7EAFC7, 0x37427DBB526D, 0x6CB891E8372C528, 0x1D2FC6D7, 0x3B7BADD53A4E, 0x325, 0x5F, 0x34AD, 0x203AFF83197E81, 0x377A2B},
+ },
+ {
+ []byte{0x2C, 0x77, 0x59, 0x98, 0x44, 0xE0, 0xD5, 0x78, 0x5F, 0xFE, 0xD1, 0x44, 0xAD, 0xCC, 0x78, 0x46, 0x69, 0x3B, 0xD5, 0xC2, 0x03, 0xE1, 0x24, 0x54, 0x8C, 0xAB, 0x06, 0x61, 0x78, 0x78, 0x89, 0x42, 0x8B, 0x1C, 0x9E, 0xA1, 0x13, 0xC8, 0x09, 0xAB, 0x7E, 0xD6, 0xC6, 0xB2, 0xAF, 0x4D, 0x1D, 0xB4, 0x85, 0xB5, 0x5D, 0x39, 0x23, 0x8E, 0x67, 0x8D, 0x48, 0xA1, 0x1B, 0x42, 0xDD, 0xBD, 0xCB, 0x53, 0xA8, 0x20, 0x50, 0xF7, 0x44, 0xE7, 0xBC, 0x7A, 0x85, 0x09, 0x71, 0x04, 0xCF, 0x81, 0xCA, 0xB4, 0x10, 0xF2, 0xBF, 0xC7, 0x7C, 0x05, 0xC3, 0x62, 0x19, 0x79, 0x04, 0x7F, 0xF8, 0x54, 0x85, 0x0E, 0x35, 0xE4, 0x64, 0x4C},
+ []uint{35, 33, 39, 14, 2, 40, 63, 64, 53, 56, 47, 42, 51, 12, 9, 43, 58, 55, 32, 52},
+ []uint64{0x163BACCC2, 0x4E0D5785, 0x7FF68A256E, 0x18F0, 0x02, 0x3349DEAE10, 0xF84915232AC1985, 0xE1E2250A2C727A84, 0x9E404D5BF6B63, 0x5957A68EDA42DA, 0x574E48E399E3, 0x148A11B42DD, 0x5EE5A9D410287, 0xBA2, 0xE7, 0x5E3D4284B88, 0x99F03956821E57, 0x7C77C05C362197, 0x9047FF85, 0x4850E35E4644C},
+ },
+ {
+ []byte{0x2F, 0x1E, 0xB8, 0x50, 0xC1, 0xF6, 0xD4, 0xD4, 0x33, 0xD8, 0x40, 0xC9, 0x5E, 0xB5, 0x29, 0x9E, 0x60, 0x65, 0xB4, 0xD2, 0x68, 0x4D, 0x3F, 0x7E, 0x0D, 0xCB, 0xE6, 0x9E, 0x0D, 0x2A, 0x4C, 0xF5, 0xD4, 0x0D, 0x20, 0x36, 0x17, 0xCB, 0xCD, 0x2A, 0xA4, 0xBE, 0x08, 0x48, 0x7C, 0xFE, 0x77, 0x28, 0xDA, 0xC0, 0xFF, 0xAC, 0x48, 0xF5, 0xCD, 0x34, 0xCD, 0x1D, 0x6E, 0x13, 0x19, 0xDD, 0x0D, 0xF1, 0x78, 0x41, 0x59, 0x87, 0xDB, 0x13, 0x44, 0xC1, 0xE0, 0xB7, 0x9C, 0x18, 0xF9, 0x4E, 0x09, 0x53, 0x99, 0x95, 0x9D, 0x7C, 0x0E, 0xDB, 0xF5, 0x7D, 0x55, 0x20, 0x19, 0x6A, 0x39, 0x30, 0xC8, 0x6E, 0xE7, 0x0E, 0xCA, 0x02},
+ []uint{15, 11, 7, 40, 53, 47, 60, 55, 29, 8, 29, 25, 53, 33, 45, 9, 30, 17, 30, 11, 7, 37, 35, 43, 25, 19, 8, 19},
+ []uint64{0x178F, 0x2E1, 0x21, 0x83EDA9A867, 0x16103257AD4A67, 0x4C0CB69A4D09, 0xA7EFC1B97CD3C1A, 0x2A4CF5D40D2036, 0x2F979A5, 0x54, 0x12F82121, 0x1E7F3B9, 0x8DAC0FFAC48F5, 0x19A699A3A, 0x1B84C677437C, 0xBC, 0x82B30FB, 0xC4D1, 0xC1E0B79, 0x60C, 0x3E, 0xA704A9CCC, 0x5675F03B6, 0x7EAFAAA4032, 0x1A8E4C3, 0x10DDC, 0xE1, 0x6CA02},
+ },
+ {
+ []byte{0x52, 0x18, 0x09, 0x9C, 0xE3, 0xF6, 0x3F, 0xA5, 0xED, 0xF7, 0x0E, 0xB9, 0x49, 0x47, 0x88, 0x47, 0x62, 0x11, 0x91, 0x9A, 0xDD, 0x33, 0x2C, 0xF9, 0x77, 0x0C, 0xFE, 0x5D, 0xBC, 0x11, 0x25, 0x0C, 0x57, 0x41, 0x2E, 0x26, 0x6A, 0x84, 0xF4, 0x6B, 0x74, 0x45, 0x74, 0x06, 0x1F, 0xAF, 0x0E, 0x4D, 0x5A, 0xBF, 0x4E, 0x02, 0x6E, 0xF5, 0x7B, 0xA4, 0xCD, 0x5F, 0xFC, 0x9B, 0xA3, 0x7D, 0x8D, 0x35, 0x11, 0xEE, 0x63, 0x6B, 0xE1, 0xC8, 0x51, 0xDB, 0x79, 0x94, 0x42, 0x4D, 0xEA, 0xAE, 0xBD, 0xC0, 0x24, 0x0C, 0x28, 0x3B, 0xCB, 0x2D, 0x67, 0x10, 0x38, 0x99, 0x8F, 0xFA, 0x9D, 0x76, 0xC5, 0xD9, 0x85, 0x0E, 0xDA, 0x45},
+ []uint{33, 3, 51, 28, 16, 63, 3, 16, 33, 58, 33, 12, 64, 41, 13, 11, 52, 27, 8, 15, 1, 20, 30, 61, 34, 39, 35},
+ []uint64{0xA4301339, 0x06, 0x1FB1FD2F6FB87, 0x5CA4A3C, 0x423B, 0x846466B74CCB3E5, 0x06, 0xE19F, 0x1976F0449, 0x10C57412E266A84, 0x1E8D6E88A, 0xE80, 0xC3F5E1C9AB57E9C0, 0x9BBD5EE933, 0xAFF, 0x726, 0xE8DF634D447B9, 0x46D7C39, 0x0A, 0x1DB7, 0x01, 0x32884, 0x26F5575E, 0x1C0240C283BCB2D6, 0x1C40E2663, 0x7F53AED8BB, 0x1850EDA45},
+ },
+ {
+ []byte{0xD6, 0x66, 0x64, 0xE0, 0x81, 0x98, 0x56, 0xB5, 0xF4, 0xA8, 0x1E, 0x12, 0x6F, 0xB0, 0x17, 0xE7, 0x91, 0xF9, 0x6C, 0x82, 0x9F, 0x22, 0xE2, 0x15, 0x5A, 0xCE, 0x73, 0x71, 0x29, 0x69, 0x8F, 0x94, 0xC7, 0xB3, 0x4F, 0x1B, 0x16, 0x28, 0xE7, 0xD6, 0x7E, 0x5F, 0xDE, 0xB6, 0x93, 0xA8, 0xDB, 0x9B, 0x44, 0x19, 0xDC, 0xE7, 0x57, 0x69, 0x4F, 0xA9, 0x33, 0x4C, 0x16, 0x5A, 0x91, 0xE4, 0x69, 0x33, 0x34, 0x93, 0x92, 0xE0, 0x00, 0xA2, 0xF2, 0xFB, 0xA9, 0xE0, 0xB5, 0xE0, 0xC0, 0x9D, 0x39, 0x52, 0xD6, 0xA4, 0x45, 0xB3, 0x9E, 0x96, 0x51, 0x44, 0xAD, 0xF0, 0x70, 0x51, 0x7D, 0xA7, 0x9F, 0xBB, 0x20, 0x41, 0x0C, 0x94},
+ []uint{49, 14, 13, 57, 39, 20, 12, 63, 47, 53, 9, 52, 41, 9, 24, 60, 44, 16, 50, 21, 42, 36, 29},
+ []uint64{0x1ACCCC9C10330, 0x2B5A, 0x1F4A, 0x103C24DF602FCF2, 0x1F96C829F2, 0x2E215, 0x5AC, 0x739B894B4C7CA63D, 0x4D3C6C58A39F, 0xB3F2FEF5B49D4, 0xDB, 0x9B4419DCE7576, 0x129F5266982, 0x196, 0xA4791A, 0x4CCD24E4B80028B, 0xCBEEA782D78, 0x3027, 0x13952D6A445B3, 0x13D2CA, 0xA256F83828, 0xBED3CFDD9, 0x410C94},
+ },
+ {
+ []byte{0xA1, 0xA6, 0x11, 0xEE, 0xBB, 0x60, 0x43, 0x9A, 0x10, 0xDA, 0x7D, 0xBB, 0x9D, 0xFC, 0x67, 0x7E, 0xE5, 0x57, 0x36, 0x8C, 0xB4, 0x20, 0x6D, 0x5A, 0xD1, 0x61, 0x1F, 0x1B, 0x1F, 0x23, 0x72, 0x26, 0xB1, 0xFF, 0x12, 0x26, 0xBB, 0x6D, 0x2B, 0x7A, 0x7E, 0x15, 0x5A, 0x2F, 0x0E, 0x17, 0xEF, 0x71, 0xCB, 0x1C, 0x18, 0xD0, 0xFE, 0x00, 0x9F, 0xC6, 0x0C, 0xB7, 0x45, 0xED, 0xF7, 0xB9, 0x93, 0xAF, 0xA5, 0x02, 0xB6, 0xFA, 0x8D, 0x7C, 0xF6, 0x2C, 0x36, 0x9A, 0x81, 0xB8, 0xCE, 0x89, 0x63, 0xAD, 0x26, 0x5C, 0x3B, 0x1B, 0xF7, 0xB8, 0xAE, 0xAF, 0x5C, 0x07, 0x47, 0x3C, 0x79, 0x14, 0x0F, 0x18, 0x35, 0xAA, 0x30, 0xCE},
+ []uint{30, 56, 32, 18, 22, 48, 9, 2, 41, 20, 9, 18, 51, 20, 28, 52, 47, 37, 24, 24, 20, 8, 19, 25, 9, 29, 24, 37, 2, 6, 33},
+ []uint64{0x2869847B, 0xAED810E684369F, 0x6EE77F19, 0x37EE5, 0x15CDA3, 0x2D081B56B458, 0x8F, 0x02, 0x6C7C8DC89A, 0xC7FC4, 0x113, 0x176DA, 0x2B7A7E155A2F0, 0xE17EF, 0x71CB1C1, 0x8D0FE009FC60C, 0x5BA2F6FBDCC9, 0x1AFA502B6F, 0xA8D7CF, 0x62C369, 0xA81B8, 0xCE, 0x44B1D, 0xD265C3, 0x163, 0xFDEE2BA, 0xBD701D, 0x39E3C8A07, 0x02, 0x0C, 0x35AA30CE},
+ },
+ {
+ []byte{0x44, 0x4D, 0xAD, 0xF6, 0xC5, 0x49, 0x84, 0x42, 0x7C, 0x1C, 0x52, 0xAB, 0x5E, 0xB4, 0xB1, 0x05, 0x2A, 0x91, 0xE7, 0xAD, 0x2C, 0x17, 0x8F, 0xCE, 0xB5, 0x0A, 0x3A, 0xAA, 0x05, 0x57, 0x36, 0xFD, 0x18, 0xA4, 0x2F, 0x32, 0x14, 0xAE, 0x60, 0x5D, 0xEE, 0x36, 0xBD, 0x7B, 0x1F, 0x6A, 0xB5, 0x10, 0x26, 0x0A, 0x19, 0xD1, 0x25, 0x53, 0xEA, 0x97, 0xF3, 0x9C, 0xE6, 0x71, 0x1E, 0xA6, 0x33, 0x98, 0x6C, 0x3E, 0xB4, 0xBD, 0x1D, 0x5B, 0xDF, 0xAB, 0xEF, 0x5D, 0xDE, 0x17, 0xB0, 0x62, 0x7D, 0x71, 0x8A, 0x36, 0xF5, 0x5B, 0xD2, 0x92, 0x54, 0xB7, 0xD0, 0x1B, 0xAD, 0x75, 0x69, 0xA0, 0x5A, 0x77, 0xFD, 0xF2, 0x81, 0xF5},
+ []uint{29, 23, 54, 22, 44, 39, 56, 7, 49, 58, 48, 51, 17, 63, 28, 7, 55, 32, 62, 56},
+ []uint64{0x889B5BE, 0x6C5498, 0x1109F0714AAD7A, 0x34B105, 0x2A91E7AD2C1, 0x3C7E75A851, 0xD5502AB9B7E8C5, 0x10, 0x17990A57302EF, 0x1C6D7AF63ED56A2, 0x4C1433A24AA, 0x3EA97F39CE671, 0x3D4C, 0x33986C3EB4BD1D5B, 0xDFABEF5, 0x6E, 0x785EC189F5C628, 0xDBD56F4A, 0x1254B7D01BAD7569, 0xA05A77FDF281F5},
+ },
+ {
+ []byte{0x0C, 0x0A, 0x46, 0x32, 0x3A, 0x2A, 0x4C, 0xD8, 0x81, 0x7D, 0x88, 0x36, 0xA9, 0x0D, 0xD2, 0xF7, 0x1C, 0x9C, 0xB9, 0xE8, 0x6B, 0x6D, 0x1D, 0xA5, 0x89, 0x16, 0x95, 0x20, 0x42, 0x46, 0x59, 0xD0, 0x4B, 0xEF, 0x6A, 0x1A, 0xD6, 0x92, 0xFF, 0x34, 0x44, 0x7D, 0x2D, 0x61, 0xC6, 0xE1, 0xAD, 0x75, 0x64, 0xDD, 0x00, 0xDA, 0x0F, 0x3E, 0xAB, 0x4D, 0x1B, 0x79, 0x55, 0x02, 0xC8, 0xF6, 0x8C, 0xF0, 0x4F, 0xAD, 0x64, 0x37, 0x08, 0xDC, 0x05, 0x4C, 0xE0, 0x3F, 0xE6, 0x0E, 0x6A, 0xC9, 0x5B, 0x82, 0x8B, 0x54, 0x2B, 0x28, 0x0F, 0xE5, 0x41, 0x4A, 0x53, 0x53, 0x81, 0x9C, 0x22, 0x75, 0xD4, 0x2A, 0x9F, 0x03, 0x14, 0x2D},
+ []uint{7, 25, 64, 47, 3, 22, 11, 18, 56, 12, 64, 63, 8, 35, 40, 12, 31, 18, 64, 51, 58, 22, 64, 5},
+ []uint64{0x06, 0xA4632, 0x3A2A4CD8817D8836, 0x5486E97B8E4E, 0x02, 0x39E86B, 0x368, 0x3B4B1, 0x22D2A40848CB3A, 0x97, 0xDED435AD25FE6888, 0x7D2D61C6E1AD7564, 0xDD, 0x6D079F5, 0x5A68DBCAA8, 0x164, 0x3DA33C13, 0x3AD64, 0x3708DC054CE03FE6, 0x73564ADC145A, 0x2856501FCA8294A, 0x1A9C0C, 0xE113AEA154F818A1, 0x0D},
+ },
+ {
+ []byte{0xB0, 0x2B, 0x72, 0xA2, 0xB5, 0xBA, 0x1F, 0xA0, 0x87, 0xEF, 0xEE, 0xE5, 0x01, 0x7F, 0x46, 0x66, 0x05, 0x7E, 0xBD, 0x0B, 0x06, 0x43, 0x3D, 0xA2, 0xCC, 0x6B, 0xA1, 0xB5, 0xBF, 0x91, 0xA7, 0x6C, 0x44, 0xC7, 0xB7, 0x7A, 0xBE, 0x20, 0xE9, 0xB1, 0xA7, 0xF9, 0x58, 0x2E, 0x92, 0x5F, 0xA2, 0xD5, 0x10, 0x98, 0xF9, 0x58, 0x1F, 0x91, 0x84, 0xCE, 0xEC, 0x53, 0x42, 0xE5, 0xBA, 0xD8, 0xC9, 0x3C, 0x5B, 0x4F, 0x7A, 0x8D, 0xC4, 0xFE, 0x6E, 0x56, 0x0A, 0x1A, 0x08, 0x2B, 0xD5, 0xFF, 0x8F, 0x28, 0xAB, 0x6A, 0xB3, 0x6C, 0x8A, 0x0F, 0x2B, 0xA5, 0x73, 0xED, 0xC7, 0x2C, 0xB9, 0xB7, 0xFD, 0x9C, 0xCA, 0xE7, 0x4E, 0xBA},
+ []uint{51, 62, 30, 50, 54, 45, 5, 36, 27, 34, 30, 27, 60, 20, 44, 43, 45, 5, 5, 12, 9, 25, 18, 50, 13},
+ []uint64{0x5815B9515ADD0, 0x3F410FDFDDCA02FE, 0x233302BF, 0x17A160C867B45, 0x2635D0DADFC8D3, 0x16C44C7B77AB, 0x1C, 0x41D3634FF, 0x1582E92, 0x17E8B5442, 0x18F9581F, 0x48C2677, 0x629A172DD6C649E, 0x2DA7B, 0xD46E27F372B, 0x286820AF57, 0x1FC79455B559, 0x16, 0x19, 0x141, 0x1CA, 0x1D2B9F6, 0x38E59, 0x1CDBFECE6573A, 0xEBA},
+ },
+ {
+ []byte{0x8E, 0xEB, 0xED, 0x77, 0xFC, 0xB9, 0x57, 0xAA, 0xC6, 0xF4, 0xEA, 0xF7, 0x59, 0xA3, 0x3F, 0xC7, 0x98, 0xF2, 0x6A, 0xA1, 0x0C, 0x08, 0xE5, 0x54, 0x8A, 0x69, 0x24, 0xE8, 0xCD, 0xD2, 0x27, 0x74, 0xC6, 0x96, 0x64, 0x1D, 0x00, 0x76, 0x21, 0xA1, 0x4F, 0xE8, 0xCF, 0x42, 0xFD, 0x51, 0x86, 0xD8, 0xBD, 0xA9, 0x28, 0x00, 0x42, 0xE9, 0x4B, 0xCB, 0xF5, 0xCF, 0x20, 0xFA, 0x96, 0x2F, 0x39, 0x86, 0x1B, 0x22, 0x73, 0x15, 0x65, 0x78, 0xFE, 0xB9, 0x12, 0xCD, 0x70, 0x2C, 0x8D, 0xE6, 0x4B, 0x08, 0x3C, 0xBB, 0x62, 0x96, 0xF9, 0xC3, 0x18, 0x29, 0xB6, 0x01, 0xEF, 0x76, 0xB6, 0x10, 0x8D, 0x00, 0x09, 0xC8, 0xBD, 0xC9},
+ []uint{23, 25, 14, 24, 54, 57, 17, 10, 55, 55, 48, 6, 52, 23, 29, 46, 62, 52, 16, 9, 28, 44, 19, 20, 12},
+ []uint64{0x4775F6, 0x177FCB9, 0x15EA, 0xB1BD3A, 0x2F759A33FC798F, 0x4D5421811CAA91, 0x9A49, 0xE8, 0x66E913BA634B32, 0x7401D886853FA, 0x33D0BF5461B6, 0x0B, 0xDA9280042E94B, 0x65FAE7, 0x120FA962, 0x3CE6186C89CC, 0x156578FEB912CD70, 0x2C8DE64B083CB, 0xB629, 0xDF, 0x3863053, 0x6C03DEED6C2, 0x8D00, 0x9C8B, 0xDC9},
+ },
+ {
+ []byte{0xCF, 0x4B, 0x63, 0xE2, 0x82, 0xA4, 0xA3, 0x18, 0x6B, 0x5B, 0x1E, 0xAA, 0x55, 0x8D, 0xBD, 0x1D, 0xE3, 0xA5, 0xAE, 0x26, 0x41, 0xBA, 0x07, 0xC5, 0x85, 0xA2, 0xB0, 0xCC, 0xA9, 0x90, 0x6B, 0xA4, 0x07, 0xBF, 0xE3, 0x01, 0x1F, 0x0D, 0x73, 0xBD, 0xC4, 0xAB, 0x03, 0xC0, 0xD7, 0xEC, 0x47, 0xCE, 0x21, 0x9C, 0x43, 0x3B, 0x88, 0xD4, 0xA3, 0xDE, 0x49, 0x70, 0x48, 0x47, 0x84, 0x97, 0xD8, 0x03, 0x34, 0x74, 0x26, 0x4B, 0x0E, 0x52, 0x32, 0x18, 0xDF, 0x36, 0xD2, 0x34, 0xA1, 0x9C, 0x04, 0x97, 0x83, 0x10, 0xC2, 0x32, 0xF8, 0x5A, 0xD2, 0xCB, 0xD8, 0x3B, 0x35, 0x58, 0x86, 0x00, 0x89, 0xDE, 0xF5, 0x7C, 0x1A, 0xFA},
+ []uint{23, 40, 60, 52, 61, 12, 53, 39, 40, 17, 40, 58, 31, 13, 58, 39, 47, 4, 38, 16, 43, 12, 4},
+ []uint64{0x67A5B1, 0xF14152518C, 0x35AD8F552AC6DE8, 0xEF1D2D71320DD, 0x7C585A2B0CCA99, 0x6B, 0x1480F7FC6023E1, 0x573BDC4AB0, 0x3C0D7EC47C, 0x1C433, 0x8867711A94, 0x1EF24B82423C24B, 0x7600CD1D, 0x132, 0x161CA46431BE6DA, 0x234A19C049, 0x3C18861197C2, 0x0D, 0x1A597B0766, 0xAB10, 0x60089DEF57C, 0x1AF, 0x0A},
+ },
+ {
+ []byte{0xC5, 0x28, 0x7C, 0xA6, 0x66, 0xF1, 0xAE, 0xF5, 0xC2, 0x0E, 0xCA, 0x71, 0xCB, 0x22, 0xE0, 0xB5, 0xA6, 0x6E, 0xC9, 0x23, 0xBE, 0xD6, 0x6A, 0x16, 0x8E, 0xC1, 0x00, 0x9B, 0xD7, 0x59, 0xA7, 0x8E, 0x68, 0x41, 0x13, 0x55, 0xAD, 0x6A, 0xC9, 0x49, 0xE1, 0x6A, 0x17, 0xBE, 0x8B, 0xA3, 0xFC, 0x81, 0x3B, 0xFB, 0x88, 0xCB, 0x1C, 0x66, 0x3F, 0x66, 0x28, 0x84, 0xB4, 0xBF, 0xFD, 0xAC, 0x65, 0x7F, 0x80, 0x67, 0x98, 0x32, 0xBF, 0x6E, 0xDC, 0xBD, 0xCD, 0x18, 0x7C, 0xBB, 0x54, 0xF9, 0xBA, 0x66, 0x79, 0x6A, 0x39, 0xC1, 0x55, 0x0E, 0x2C, 0x2B, 0x08, 0x10, 0x7F, 0x0A, 0x8A, 0xFA, 0xE3, 0x24, 0x31, 0x99, 0xFE, 0xAA},
+ []uint{29, 64, 55, 11, 37, 3, 50, 2, 21, 56, 17, 35, 48, 42, 61, 26, 3, 16, 19, 11, 9, 64, 50, 11, 29, 14, 17},
+ []uint64{0x18A50F94, 0xCCDE35DEB841D94E, 0x1CB22E0B5A66EC, 0x491, 0x1BED66A168, 0x07, 0x1820137AEB34F, 0x00, 0xE6841, 0x1355AD6AC949E1, 0xD42F, 0x3E8BA3FC8, 0x13BFB88CB1C6, 0x18FD98A212D, 0x5FFED632BFC033C, 0x30657ED, 0x06, 0xDCBD, 0x668C3, 0x72E, 0x1AA, 0x7CDD333CB51CE0AA, 0x21C58561020FE, 0xA8, 0x15F5C648, 0x18CC, 0x1FEAA},
+ },
+ {
+ []byte{0x69, 0x50, 0x9D, 0x23, 0xBD, 0xE7, 0x5B, 0x7F, 0x45, 0x9A, 0xD4, 0xD8, 0x62, 0x06, 0xCD, 0x3E, 0x7F, 0x32, 0xB5, 0x41, 0x25, 0x12, 0xD2, 0x13, 0xC9, 0x91, 0x44, 0x49, 0x86, 0x50, 0x8E, 0xCF, 0x38, 0x1E, 0x85, 0x65, 0xCB, 0x68, 0x6A, 0xFF, 0x1E, 0x03, 0x28, 0x0A, 0xB0, 0x93, 0xB6, 0xD5, 0x50, 0x15, 0x04, 0xB1, 0x6C, 0x71, 0xF1, 0xE7, 0xFE, 0xC9, 0x10, 0x89, 0xD6, 0xCE, 0x3F, 0x4F, 0xFF, 0x2F, 0xE8, 0xE7, 0xD1, 0x88, 0x19, 0x74, 0xEF, 0xC4, 0xD8, 0xAA, 0x49, 0x77, 0x09, 0xE9, 0x73, 0x5C, 0x75, 0xCB, 0x2F, 0x97, 0xB2, 0xF7, 0x8A, 0x71, 0x1C, 0xC5, 0x9D, 0x72, 0x16, 0x66, 0x18, 0x39, 0x3F, 0xBF},
+ []uint{47, 4, 10, 61, 39, 3, 60, 41, 7, 5, 46, 14, 54, 21, 57, 14, 48, 57, 4, 56, 60, 34, 33, 25},
+ []uint64{0x34A84E91DEF3, 0x0A, 0x36F, 0x1D166B5361881B34, 0x7CFE656A82, 0x02, 0x512D213C9914449, 0x10CA11D9E70, 0x1E, 0x10, 0x2B2E5B4357F8, 0x3C06, 0x14055849DB6AA8, 0x1504B, 0x2D8E3E3CFFD922, 0x44E, 0xB671FA7FF97F, 0x8E7D1881974EFC, 0x04, 0xD8AA497709E973, 0x5C75CB2F97B2F78, 0x29C473167, 0xB90B330C, 0x393FBF},
+ },
+ {
+ []byte{0x66, 0x39, 0x3F, 0x83, 0xCF, 0x72, 0x88, 0x33, 0xFB, 0xC8, 0x2F, 0x5D, 0x9E, 0x20, 0xD3, 0xF3, 0x8B, 0x9D, 0xC9, 0xE8, 0xEC, 0xC1, 0x77, 0xD0, 0x76, 0xFF, 0x95, 0x84, 0x0E, 0x97, 0x97, 0x1F, 0x62, 0x6B, 0x24, 0x42, 0x72, 0x39, 0x75, 0x5B, 0x1C, 0x65, 0xA4, 0x91, 0x43, 0xDF, 0xCA, 0x1D, 0x4F, 0x15, 0x64, 0x1E, 0xA5, 0xFC, 0xBF, 0x4B, 0x2D, 0x5D, 0xD9, 0x3F, 0xC8, 0xD9, 0x09, 0x15, 0x81, 0x71, 0xF7, 0x2D, 0x0C, 0xAD, 0xE1, 0x6F, 0x76, 0x92, 0x48, 0x1F, 0xF7, 0x63, 0xC5, 0x4E, 0x9B, 0x0E, 0xB7, 0x1F, 0xE3, 0x9C, 0x71, 0x1D, 0x85, 0xB6, 0x23, 0x48, 0x3D, 0x5B, 0x27, 0x54, 0xD0, 0xE6, 0xFF, 0x66},
+ []uint{63, 43, 6, 51, 18, 20, 8, 45, 60, 24, 54, 8, 60, 4, 35, 38, 42, 26, 28, 18, 25, 15, 28, 8, 16, 57},
+ []uint64{0x331C9FC1E7B94419, 0x7EF20BD7678, 0x20, 0x69F9C5CEE4F47, 0x1982E, 0xFA0ED, 0xFF, 0x56103A5E5C7, 0xD89AC9109C8E5D5, 0x6C7196, 0x249143DFCA1D4F, 0x15, 0x641EA5FCBF4B2D5, 0x0D, 0x6C9FE46C8, 0x122B02E3EE, 0x168656F0B7B, 0x2D24903, 0xFEEC78A, 0x274D8, 0xEB71FE, 0x1CE3, 0x88EC2DB, 0x11, 0xA41E, 0x15B2754D0E6FF66},
+ },
+ {
+ []byte{0x8F, 0x63, 0xBD, 0x4A, 0x79, 0xCC, 0x5B, 0x8B, 0x94, 0xD1, 0x09, 0xEC, 0xEA, 0x03, 0x58, 0xA1, 0xED, 0x5C, 0x72, 0x41, 0xBE, 0x2E, 0x84, 0x52, 0x1F, 0xE0, 0x20, 0x0F, 0x6E, 0x34, 0x3C, 0xEF, 0xC2, 0xD4, 0x1B, 0x4C, 0x52, 0x99, 0x33, 0x4F, 0x53, 0xB0, 0xD7, 0x54, 0x4B, 0x59, 0x2E, 0xEB, 0x04, 0x59, 0xAE, 0xFF, 0x4E, 0x47, 0xE1, 0x06, 0x8F, 0xB2, 0xF2, 0xB2, 0xB4, 0x73, 0x3B, 0xDA, 0x65, 0xBF, 0x04, 0x74, 0xAB, 0xE0, 0x8C, 0x51, 0x04, 0x7A, 0x68, 0x7D, 0xFE, 0xF1, 0xF1, 0xC6, 0x87, 0xD9, 0x20, 0xEE, 0x9C, 0xD7, 0x05, 0xB7, 0x7F, 0xB2, 0x9E, 0xC7, 0xB7, 0x1E, 0x28, 0x85, 0xE0, 0x86, 0xA8, 0x3C},
+ []uint{7, 18, 6, 31, 48, 10, 41, 63, 35, 22, 27, 13, 22, 64, 30, 9, 14, 53, 18, 47, 8, 62, 30, 18, 41, 56, 7},
+ []uint64{0x47, 0x2C77A, 0x25, 0x1E7316E2, 0xE534427B3A80, 0x358, 0x143DAB8E483, 0x3E2E84521FE0200F, 0x371A1E77E, 0x5A836, 0x4C52993, 0x69E, 0x29D86B, 0xAA25AC9775822CD7, 0x1FE9C8FC, 0x41, 0x28FB, 0x5E56568E677B4, 0x32DF8, 0x11D2AF823144, 0x11, 0x3A687DFEF1F1C687, 0x36483BA7, 0xD705, 0x16EFF653D8F, 0x6E3C510BC10D50, 0x3C},
+ },
+ {
+ []byte{0x68, 0xBC, 0xC2, 0x6E, 0x0B, 0xE7, 0x1E, 0x5A, 0x9E, 0xE4, 0x64, 0xB1, 0xF7, 0x37, 0xA7, 0xF8, 0x1B, 0x6E, 0xD3, 0x99, 0x2A, 0xE4, 0x42, 0x43, 0xA7, 0x5E, 0xD0, 0x02, 0x1D, 0x64, 0x72, 0x99, 0x26, 0xF5, 0x76, 0xD1, 0xD5, 0x0D, 0x11, 0x30, 0x71, 0x58, 0x4F, 0xD3, 0xAB, 0x73, 0xBB, 0xD0, 0x1C, 0xE9, 0xCA, 0x37, 0x41, 0xA1, 0xF6, 0x76, 0x13, 0xD6, 0x7A, 0xF2, 0xA0, 0x76, 0x66, 0xC3, 0x3B, 0x3A, 0x9C, 0xE8, 0x28, 0x50, 0x9A, 0x76, 0x2C, 0xFC, 0x48, 0x2A, 0x23, 0xD9, 0xF4, 0x39, 0x9F, 0xC1, 0x85, 0x49, 0xFE, 0xFD, 0x2C, 0x14, 0x73, 0x3D, 0x08, 0xE9, 0x15, 0x9E, 0xC1, 0x86, 0xA5, 0x27, 0xAB, 0x9D},
+ []uint{7, 27, 15, 37, 13, 26, 25, 4, 56, 38, 25, 11, 13, 38, 26, 32, 51, 7, 53, 13, 46, 53, 41, 50, 41, 52},
+ []uint64{0x34, 0x2F309B8, 0x17CE, 0x796A7B919, 0x58F, 0x2E6F4FF, 0x6DBB4, 0x0E, 0x64AB91090E9D7B, 0x10021D6472, 0x1324DEA, 0x76D, 0x3AA, 0x6889838AC, 0x9FA756, 0xE777A039, 0x69CA3741A1F67, 0x30, 0x13D67AF2A07666, 0x1867, 0x19D4E7414284, 0x1A762CFC482A23, 0x1B3E8733F83, 0x2A4FF7E960A3, 0x133D08E9159, 0xEC186A527AB9D},
+ },
+ {
+ []byte{0xDE, 0xFA, 0x7D, 0x18, 0x91, 0x5F, 0xD5, 0x6A, 0x70, 0x0D, 0xEA, 0x2C, 0x70, 0x3E, 0xC2, 0x17, 0x65, 0x69, 0xB9, 0x94, 0x4D, 0xEF, 0x61, 0x47, 0xFB, 0x07, 0x57, 0x14, 0x60, 0xEE, 0x6F, 0x2C, 0x50, 0x2C, 0xDC, 0x56, 0xAC, 0x5A, 0x1E, 0xA6, 0x3D, 0xAE, 0xEB, 0xEB, 0x52, 0xA0, 0x8F, 0xEB, 0x2C, 0x01, 0x55, 0x6B, 0x7D, 0x29, 0x15, 0x06, 0xB9, 0x12, 0x9E, 0x88, 0x15, 0x06, 0xE5, 0x81, 0x77, 0x61, 0x3E, 0x6A, 0x0E, 0xE4, 0xA9, 0xE2, 0x73, 0x78, 0x7A, 0x04, 0x3A, 0x8E, 0xB2, 0x68, 0x3E, 0x97, 0xFE, 0x8B, 0xA7, 0x54, 0x7C, 0x44, 0xCD, 0x50, 0x75, 0x8D, 0x1E, 0x3C, 0xF8, 0x0F, 0x09, 0x7A, 0x30, 0x38},
+ []uint{18, 55, 46, 36, 6, 40, 36, 28, 62, 26, 58, 8, 62, 57, 61, 31, 4, 14, 55, 59, 6, 5, 27},
+ []uint64{0x37BE9, 0x7A3122BFAAD4E0, 0x6F516381F61, 0xBB2B4DCC, 0x28, 0x9BDEC28FF6, 0xEAE28C1D, 0xCDE58A0, 0x166E2B562D0F531E, 0x35DD7D6, 0x295047F59600AAB, 0x5B, 0x3A522A0D72253D10, 0x541B9605DD84F9, 0x15077254F139BC3D, 0x10EA3AC, 0x09, 0x283E, 0x4BFF45D3AA3E22, 0x33541D63478F3E0, 0x0F, 0x01, 0x17A3038},
+ },
+ {
+ []byte{0x1F, 0x14, 0x9C, 0x3B, 0x12, 0xAB, 0xA7, 0x1E, 0x56, 0x9C, 0x0F, 0x6B, 0xD7, 0x06, 0x53, 0x96, 0xD3, 0x93, 0x66, 0x48, 0x51, 0x47, 0x3B, 0x8B, 0x73, 0x6D, 0x56, 0x25, 0xE1, 0x37, 0x33, 0x5E, 0x50, 0x51, 0xD5, 0xA2, 0xDF, 0x36, 0x71, 0x08, 0xA4, 0x45, 0xA2, 0xD8, 0x7A, 0xE4, 0x71, 0x2C, 0x8F, 0x2F, 0x58, 0x1C, 0x92, 0x53, 0x36, 0x72, 0xD1, 0x3E, 0xED, 0xDB, 0xBE, 0x81, 0x6E, 0xA5, 0x3C, 0x88, 0xE6, 0x86, 0xA2, 0xFD, 0x2C, 0xEC, 0xE2, 0x87, 0x3C, 0x4E, 0xA8, 0xB9, 0x30, 0xB6, 0xD2, 0x44, 0xFD, 0x7C, 0xDD, 0x9D, 0x68, 0x7E, 0xE3, 0xC0, 0xE1, 0x55, 0xB5, 0x46, 0xEE, 0x6E, 0x3A, 0xEC, 0xC0, 0xEE},
+ []uint{27, 22, 22, 27, 60, 40, 63, 9, 2, 14, 31, 30, 40, 57, 18, 25, 52, 61, 35, 27, 25, 51, 9, 40, 13},
+ []uint64{0xF8A4E1, 0x362557, 0x138F2B, 0x2703DAF, 0x5C194E5B4E4D992, 0x1451CEE2DC, 0x6DAAC4BC26E66BCA, 0x14, 0x01, 0x3568, 0x5BE6CE21, 0x5222D16, 0xC3D7238964, 0xF2F581C9253367, 0xB44F, 0x176EDDF, 0x40B7529E44734, 0x6A2FD2CECE2873C, 0x27545C985, 0x5B4913F, 0xBE6ECE, 0x5A1FB8F038556, 0x1AA, 0x377371D766, 0xEE},
+ },
+ {
+ []byte{0xC6, 0x50, 0x5B, 0xDC, 0x8F, 0x17, 0x18, 0xFC, 0x74, 0xB0, 0xA2, 0x6B, 0x88, 0x04, 0x43, 0x34, 0x39, 0xEE, 0x82, 0x49, 0x11, 0xCE, 0x55, 0x79, 0xC0, 0xBE, 0xC5, 0x9A, 0x68, 0xA7, 0xC3, 0xF3, 0x10, 0x6D, 0xCC, 0x36, 0x5A, 0xCE, 0x18, 0x02, 0xE0, 0x3F, 0x72, 0xCF, 0x15, 0xBF, 0xE6, 0x8E, 0x53, 0xA8, 0xE8, 0xC7, 0x8A, 0xF2, 0x36, 0x8F, 0x23, 0xB4, 0xF1, 0x2A, 0xF2, 0xBB, 0x12, 0x3E, 0x89, 0xDA, 0x20, 0x08, 0x70, 0x08, 0xC3, 0xD7, 0x29, 0x87, 0x29, 0xA9, 0x3C, 0x63, 0x28, 0x7B, 0x85, 0xE4, 0x58, 0x91, 0x9A, 0x28, 0xCD, 0x52, 0x3D, 0x8F, 0x57, 0xC6, 0xE6, 0xD2, 0xC7, 0x4E, 0x8C, 0x8C, 0x94, 0x0B},
+ []uint{30, 9, 43, 58, 57, 60, 39, 34, 10, 51, 14, 9, 33, 26, 38, 8, 24, 11, 40, 60, 41, 44, 40, 14, 7},
+ []uint64{0x319416F7, 0x47, 0x45C63F1D2C2, 0x226B8804433439E, 0x1D0492239CAAF38, 0x17D8B34D14F87E6, 0x106DCC365A, 0x338600B80, 0x3F7, 0x1678ADFF34729, 0x351D, 0x31, 0x1C5791B47, 0x24769E2, 0x15795D891F, 0x44, 0xED1004, 0x1C0, 0x230F5CA61C, 0xA6A4F18CA1EE179, 0x2C48CD1466, 0xA91EC7ABE37, 0x36963A7464, 0x1928, 0x0B},
+ },
+ {
+ []byte{0x92, 0x34, 0xDC, 0xA7, 0x57, 0x47, 0x83, 0xFB, 0x4C, 0x08, 0x2D, 0x84, 0xED, 0x7A, 0xD1, 0x7A, 0x8F, 0xDF, 0x10, 0xAE, 0xD4, 0x58, 0xEB, 0xF7, 0x69, 0xE8, 0x94, 0x41, 0x97, 0xAC, 0x78, 0x04, 0x9C, 0x5E, 0xB3, 0xB9, 0x0C, 0xE3, 0x48, 0xC5, 0x45, 0x1A, 0xBB, 0x8D, 0x21, 0xA0, 0x4B, 0x77, 0xE1, 0x01, 0x06, 0x6D, 0x89, 0x37, 0xD8, 0xB9, 0xCF, 0xD3, 0x94, 0xD0, 0xFD, 0xF8, 0xE2, 0xC5, 0x33, 0x3E, 0xAF, 0x7F, 0x9B, 0xF1, 0xDE, 0x2D, 0xF7, 0x10, 0x3A, 0xBA, 0xD9, 0x17, 0xF8, 0x79, 0x7A, 0xF4, 0xAC, 0x44, 0x60, 0x5E, 0x2E, 0xA5, 0x87, 0xC9, 0x9C, 0x7D, 0x0A, 0x42, 0xAC, 0xBF, 0x90, 0x0A, 0x83, 0xB9},
+ []uint{41, 57, 52, 49, 23, 39, 53, 1, 6, 37, 2, 19, 13, 10, 52, 17, 38, 20, 20, 45, 36, 56, 22, 20, 49, 5, 18},
+ []uint64{0x12469B94EAE, 0x11E0FED3020B613, 0xB5EB45EA3F7C4, 0x576A2C75FBB4, 0x7A2510, 0x32F58F0093, 0x117ACEE4338D23, 0x00, 0x0A, 0x1146AEE348, 0x01, 0x5025B, 0x17E1, 0x04, 0x19B624DF62E73, 0x1E9CA, 0x1A1FBF1C58, 0xA667D, 0x5EFF3, 0xFC778B7DC40, 0xEAEB645FE, 0x1E5EBD2B111817, 0x22EA58, 0x7C99C, 0xFA1485597F20, 0x02, 0x283B9},
+ },
+ {
+ []byte{0x14, 0x51, 0xA2, 0xCB, 0xC5, 0x75, 0xFD, 0x6D, 0xAA, 0x55, 0x35, 0x8A, 0x0C, 0x63, 0xD7, 0xD0, 0x6A, 0x88, 0x56, 0x78, 0xDE, 0x38, 0xA8, 0xAA, 0xB0, 0x3A, 0x8A, 0xD4, 0xCC, 0x91, 0x9A, 0x6D, 0xA2, 0xC9, 0xA5, 0x3A, 0xAB, 0x4C, 0xC4, 0xFC, 0x3C, 0xB2, 0x44, 0xBB, 0x3C, 0xFB, 0xF8, 0x62, 0x82, 0x90, 0xF8, 0x5E, 0x6A, 0x3C, 0x6A, 0x14, 0x61, 0x7E, 0xA8, 0x0C, 0x3B, 0x7F, 0x00, 0xF8, 0x18, 0x14, 0xBD, 0x13, 0xA3, 0xC6, 0xE6, 0xF1, 0xB0, 0x9F, 0x91, 0xF7, 0x16, 0xC9, 0xDB, 0x9D, 0xC8, 0xB8, 0x96, 0xA0, 0x22, 0x95, 0xF3, 0x39, 0x8C, 0xE8, 0x6D, 0xDC, 0xE2, 0x75, 0xAD, 0xC3, 0xC9, 0x2E, 0x2A, 0xDC},
+ []uint{9, 52, 26, 1, 3, 3, 39, 45, 14, 59, 41, 42, 38, 61, 61, 57, 29, 56, 58, 6, 11, 32, 33, 17, 7},
+ []uint64{0x28, 0xA345978AEBFAD, 0x2D52A9A, 0x01, 0x04, 0x02, 0x418C7AFA0D, 0xA2159E378E2, 0x28AA, 0x581D456A6648CD3, 0xDA2C9A53AA, 0x2D3313F0F2C, 0x244BB3CFBF, 0x10C50521F0BCD478, 0x1A85185FAA030EDF, 0x1807C0C0A5E89D1, 0x1C6E6F1B, 0x9F91F716C9DB9, 0x3722E25A808A57C, 0x33, 0x4C6, 0x7436EE71, 0x75ADC3C9, 0x5C55, 0x5C},
+ },
+ {
+ []byte{0x71, 0x4F, 0x73, 0x51, 0xAA, 0x39, 0xC9, 0x4F, 0xF7, 0x6E, 0x45, 0x35, 0x07, 0x37, 0x78, 0x28, 0x44, 0x01, 0x14, 0xE7, 0xCA, 0x39, 0x71, 0x8B, 0x93, 0x42, 0x99, 0x23, 0x8B, 0x38, 0x34, 0x2F, 0xD9, 0x59, 0xF7, 0xFA, 0x8F, 0x96, 0x99, 0x23, 0x4D, 0x5D, 0x6D, 0xF2, 0xDD, 0xEB, 0x60, 0xF6, 0x7F, 0x01, 0xBA, 0x5D, 0xAD, 0x7E, 0xD2, 0x2C, 0x34, 0x11, 0x1E, 0xD7, 0x77, 0xAE, 0x59, 0x52, 0x8B, 0xAC, 0x48, 0x9F, 0xF3, 0x26, 0xCF, 0x56, 0xE2, 0x16, 0x56, 0x15, 0xB1, 0xDE, 0xDC, 0x0E, 0x00, 0x35, 0x4A, 0x59, 0x72, 0x56, 0x44, 0xD7, 0x22, 0x77, 0x2E, 0x78, 0x26, 0x3E, 0x0E, 0xF2, 0xB7, 0x37, 0x5B, 0x86},
+ []uint{49, 54, 59, 50, 64, 64, 51, 12, 33, 26, 54, 4, 29, 33, 32, 61, 44, 41, 18, 22},
+ []uint64{0xE29EE6A35473, 0x24A7FBB7229A83, 0x4DDE0A11004539F, 0xA39718B93429, 0x9238B38342FD959F, 0x7FA8F9699234D5D6, 0x6F96EF5B07B3F, 0x80D, 0x1A5DAD7ED, 0x8B0D04, 0x11ED777AE59528, 0x0B, 0x158913FE, 0xC9B3D5B8, 0x8595856C, 0xEF6E07001AA52CB, 0x92B226B913B, 0x12E78263E0E, 0x3CADC, 0x375B86},
+ },
+ {
+ []byte{0x50, 0xFB, 0x8B, 0x19, 0xF8, 0xE7, 0x6D, 0xEF, 0xCC, 0x78, 0x91, 0x98, 0x77, 0xAD, 0x00, 0xA7, 0x6F, 0x35, 0x25, 0xA8, 0x8F, 0xC2, 0x2E, 0x07, 0x1C, 0x95, 0x09, 0x10, 0xED, 0xCC, 0x86, 0x3C, 0xF1, 0x04, 0x2C, 0xC6, 0xC6, 0xE7, 0x89, 0xC1, 0x7F, 0x34, 0x16, 0xBE, 0x45, 0x47, 0xD8, 0xE7, 0x84, 0x74, 0x30, 0x91, 0x36, 0xDD, 0x88, 0x00, 0xB9, 0x73, 0x22, 0xA9, 0xF1, 0x72, 0x5F, 0x6B, 0x61, 0x1F, 0x09, 0xFA, 0xB8, 0x8F, 0xE1, 0x24, 0xBB, 0xDF, 0xB9, 0x43, 0xD8, 0x46, 0x3E, 0x4C, 0xD9, 0x77, 0x56, 0xD5, 0x4F, 0x98, 0x7D, 0x61, 0xD6, 0xFA, 0x27, 0xB6, 0xA1, 0x95, 0x8A, 0xB2, 0x40, 0x6E, 0x1F, 0xC2},
+ []uint{9, 19, 15, 27, 49, 35, 15, 38, 48, 39, 29, 49, 62, 51, 3, 17, 38, 37, 35, 13, 6, 33, 54, 8, 14, 35, 22},
+ []uint64{0xA1, 0x7B8B1, 0x4FC7, 0x1DB7BF3, 0x3C48CC3BD680, 0x29DBCD496, 0x511F, 0x2117038E4A, 0x848876E6431E, 0x3C410B31B1, 0x173C4E0B, 0x1F3416BE4547D, 0x239E11D0C244DB76, 0x100172E64553E, 0x01, 0xE4BE, 0x35B08F84FD, 0xB88FE124B, 0x5EFDCA1EC, 0x463, 0x39, 0x66CBBAB6, 0x2A9F30FAC3ADF4, 0x4F, 0x1B50, 0x6562AC901, 0x2E1FC2},
+ },
+ {
+ []byte{0xCB, 0x0B, 0xBC, 0xEA, 0x8E, 0x98, 0xFC, 0x67, 0x6A, 0x13, 0x54, 0x10, 0x90, 0xE9, 0xAF, 0x4D, 0xA5, 0x28, 0xAD, 0x14, 0xD3, 0x62, 0x21, 0x81, 0x4F, 0x15, 0x40, 0x65, 0x32, 0x37, 0x39, 0x8C, 0x71, 0x38, 0xBE, 0xF8, 0x37, 0x6B, 0x96, 0x5A, 0x2C, 0x19, 0x6F, 0xF3, 0xCF, 0xF9, 0x08, 0xC3, 0x4B, 0xAB, 0x9C, 0xB3, 0xA2, 0xE7, 0x62, 0x61, 0xBC, 0x59, 0x83, 0x95, 0x5B, 0x22, 0x0B, 0x1B, 0x7D, 0x7B, 0xDE, 0xF7, 0x96, 0xC0, 0x30, 0x29, 0xEF, 0x4E, 0x46, 0xE8, 0x8D, 0x24, 0xFC, 0x0B, 0x5E, 0xC1, 0x40, 0x6E, 0xA6, 0x81, 0xB1, 0x66, 0x15, 0x78, 0xED, 0xF6, 0x3A, 0x6D, 0x3B, 0xC6, 0x29, 0x3B, 0x29, 0xAD},
+ []uint{34, 62, 46, 7, 8, 55, 14, 33, 30, 14, 16, 63, 29, 31, 39, 52, 60, 2, 21, 4, 60, 45, 9, 51, 15},
+ []uint64{0x32C2EF3AA, 0xE98FC676A135410, 0x243A6BD3694A, 0x15, 0xA2, 0x4D36221814F154, 0x194, 0x191B9CC63, 0x22717DF0, 0x1BB5, 0xCB2D, 0xB065BFCF3FE4230, 0x1A5D5CE5, 0x4E8B9D89, 0x4378B3072A, 0xB6441636FAF7B, 0xDEF2D806053DE9C, 0x02, 0x6E88D, 0x02, 0x4FC0B5EC1406EA6, 0x10362CC2AF1D, 0x17D, 0x474DA778C5276, 0x29AD},
+ },
+ {
+ []byte{0x65, 0x00, 0xA4, 0x4F, 0x09, 0x6B, 0x77, 0xDC, 0xB3, 0x75, 0xDA, 0x0C, 0xEF, 0x14, 0x65, 0x7B, 0x1B, 0xDF, 0x21, 0x1E, 0xBA, 0x98, 0xC0, 0xD0, 0x34, 0xB3, 0x75, 0x8F, 0x90, 0x17, 0xF0, 0x73, 0x99, 0x7D, 0x1A, 0x89, 0xDF, 0x48, 0xEE, 0xF4, 0x7C, 0x23, 0x93, 0x2B, 0xFF, 0xFE, 0x5A, 0x3C, 0x4F, 0x9D, 0x4C, 0x22, 0x2E, 0xD0, 0x31, 0x23, 0xD6, 0x00, 0xA2, 0x63, 0xD8, 0x78, 0xAD, 0x90, 0xB3, 0xF2, 0x8B, 0x38, 0x45, 0xB3, 0x1A, 0xB7, 0x5B, 0xD3, 0x5A, 0x93, 0x43, 0x65, 0x33, 0xB2, 0xB4, 0x74, 0x2C, 0x87, 0x63, 0x15, 0xCF, 0x9F, 0x20, 0x6D, 0xCF, 0xE7, 0x49, 0xFD, 0x32, 0x85, 0x0D, 0x4C, 0x56, 0x23},
+ []uint{33, 45, 36, 59, 14, 38, 44, 46, 39, 5, 16, 58, 26, 45, 28, 1, 48, 46, 26, 54, 57, 19, 17},
+ []uint64{0xCA01489E, 0x25ADDF72CDD, 0x76833BC51, 0x4AF637BE423D753, 0x606, 0x206966EB1F, 0x202FE0E732F, 0x28D44EFA4777, 0x51F08E4CAF, 0x1F, 0xFF2D, 0x789F3A98445DA0, 0x1891EB0, 0xA263D878AD, 0x90B3F28, 0x01, 0x6708B66356EB, 0x1E9AD49A1B29, 0x276568E, 0x21643B18AE7CF9, 0x6DCFE749FD328, 0x286A6, 0x5623},
+ },
+ {
+ []byte{0x31, 0xB1, 0x41, 0xCC, 0x16, 0x3C, 0xA8, 0x45, 0x95, 0x99, 0x28, 0x22, 0xBC, 0xDB, 0x79, 0xB1, 0x73, 0x27, 0xF2, 0x83, 0xFF, 0x6D, 0x48, 0x0D, 0xAF, 0x90, 0x08, 0xF8, 0x9C, 0xD3, 0x54, 0x39, 0x63, 0x63, 0x75, 0xD7, 0xA0, 0x88, 0x47, 0x1A, 0x8A, 0x0F, 0x3D, 0x0E, 0x92, 0x7B, 0x6E, 0x5D, 0x01, 0x4F, 0x0E, 0x59, 0x79, 0xF0, 0x4B, 0xDC, 0x53, 0x58, 0x2A, 0x6E, 0x98, 0xC9, 0x62, 0xAD, 0x24, 0x08, 0xB7, 0x37, 0xAB, 0x65, 0x9A, 0x2A, 0x59, 0x3E, 0xE4, 0x29, 0x9C, 0x10, 0xC3, 0x45, 0xD7, 0x6A, 0x1C, 0x4D, 0xC3, 0x85, 0xFF, 0x94, 0x8E, 0x56, 0x3B, 0x21, 0x7A, 0x3D, 0x6C, 0x7D, 0xE3, 0x97, 0x37, 0x6C},
+ []uint{37, 10, 30, 25, 3, 25, 7, 11, 15, 8, 19, 20, 25, 37, 45, 63, 33, 52, 55, 12, 63, 24, 1, 31, 53, 25, 54, 17},
+ []uint64{0x636283982, 0x31E, 0x1508B2B3, 0x4A08AF, 0x01, 0x16DE6C5, 0x66, 0x27F, 0x141F, 0xFB, 0x35203, 0x6BE40, 0x47C4E6, 0x1354396363, 0xEBAF41108E3, 0x28A0F3D0E927B6E5, 0x1A029E1CB, 0x2F3E097B8A6B0, 0x2A6E98C962AD24, 0x8B, 0x39BD5B2CD152C9F7, 0x214CE0, 0x01, 0x61A2EBB, 0xA1C4DC385FF94, 0x11CAC76, 0x10BD1EB63EF1CB, 0x1376C},
+ },
+ {
+ []byte{0x8B, 0x89, 0x8A, 0x74, 0xAA, 0x17, 0xFF, 0xDA, 0x92, 0xDF, 0xB8, 0xC9, 0xFE, 0xB4, 0xB6, 0x84, 0x9C, 0x55, 0x64, 0x82, 0x41, 0x81, 0xFE, 0x23, 0xF1, 0xAC, 0x76, 0x5D, 0x55, 0xC8, 0x13, 0x6C, 0x5A, 0x0E, 0xAA, 0x71, 0x12, 0xFA, 0xED, 0x0C, 0x56, 0x2F, 0xD9, 0x70, 0x38, 0x7F, 0x8D, 0x06, 0x00, 0x3C, 0xD8, 0xB7, 0xE4, 0x99, 0x69, 0xD4, 0xFC, 0xA0, 0x35, 0x5D, 0x9F, 0xD2, 0x59, 0x32, 0x93, 0x60, 0x4A, 0x57, 0xCD, 0x93, 0x94, 0x74, 0x6F, 0x99, 0x5C, 0x49, 0x58, 0x62, 0xE5, 0xF3, 0x59, 0x9B, 0x33, 0xFE, 0x9D, 0x86, 0x2D, 0xA3, 0x0A, 0xB8, 0xB8, 0x7E, 0xFB, 0x51, 0xD0, 0x16, 0xF6, 0xF3, 0x22, 0x22},
+ []uint{31, 27, 6, 12, 61, 3, 47, 47, 8, 8, 15, 29, 29, 32, 27, 22, 42, 51, 14, 52, 6, 25, 6, 22, 51, 62, 60, 5},
+ []uint64{0x45C4C53A, 0x2A85FFF, 0x1A, 0x92D, 0x1F7193FD696D0938, 0x05, 0x2B24120C0FF1, 0xFC6B1D97557, 0x20, 0x4D, 0x58B4, 0x3AA9C44, 0x17D76862, 0xB17ECB81, 0x61FE341, 0x2003CD, 0x22DF9265A75, 0x1F9406ABB3FA4, 0x2C99, 0x49B0252BE6C9C, 0x28, 0x1D1BE65, 0x1C, 0x125618, 0x5CBE6B33667FD, 0xEC316D1855C5C3F, 0x7DA8E80B7B79911, 0x02},
+ },
+ {
+ []byte{0xC8, 0x02, 0x2F, 0x55, 0xFC, 0x45, 0xDF, 0xA9, 0x4D, 0x04, 0xDC, 0x73, 0xDF, 0x5C, 0x82, 0x14, 0x9E, 0x65, 0xC8, 0xFF, 0x12, 0x5E, 0x15, 0x8F, 0xCA, 0x0A, 0xC9, 0xB9, 0x59, 0x99, 0x64, 0x7A, 0x6A, 0xE6, 0x49, 0x9C, 0x74, 0x72, 0xCD, 0xB3, 0x6F, 0xCF, 0x99, 0x02, 0xB1, 0x2C, 0xB4, 0x78, 0xF4, 0x43, 0x1C, 0xB9, 0xB0, 0xE6, 0xC6, 0x94, 0xF3, 0x01, 0x66, 0x13, 0x5E, 0x2A, 0xF9, 0xD0, 0x33, 0xFC, 0x77, 0xC4, 0xFA, 0x0F, 0x7B, 0xFD, 0x1C, 0xC2, 0x77, 0xED, 0x37, 0xAA, 0x97, 0x3D, 0x1E, 0x86, 0x96, 0x9C, 0x67, 0x12, 0xC2, 0x8B, 0xA7, 0xCB, 0xC1, 0x35, 0xCE, 0x80, 0xF2, 0x4F, 0xCB, 0xB8, 0x9F, 0xE4},
+ []uint{28, 39, 42, 11, 32, 11, 2, 11, 58, 55, 37, 23, 17, 57, 41, 8, 22, 21, 23, 3, 1, 49, 45, 27, 46, 48, 9, 34},
+ []uint64{0xC8022F5, 0x2FE22EFD4A, 0x1A09B8E7BEB, 0x482, 0x149E65C8, 0x7F8, 0x02, 0x25E, 0x563F282B26E566, 0x32C8F4D5CC9338, 0x1D1CB36CDB, 0x79F320, 0xAC4B, 0x5A3C7A218E5CD8, 0xE6C694F301, 0x66, 0x4D78A, 0x17CE81, 0x4FF1DF, 0x00, 0x01, 0x7D07BDFE8E61, 0x77ED37AA973, 0x68F434B, 0x138CE2585174, 0xF97826B9D01E, 0x93, 0x3CBB89FE4},
+ },
+ {
+ []byte{0x69, 0x18, 0xCA, 0x1F, 0x76, 0xD9, 0x00, 0xA8, 0xC4, 0x7C, 0x90, 0xB8, 0xC9, 0x4B, 0xF2, 0xE1, 0xEF, 0xFA, 0x7C, 0x5A, 0x6E, 0xB2, 0xDA, 0x4A, 0x86, 0x2E, 0x93, 0x5A, 0xB0, 0x61, 0x15, 0x72, 0xDD, 0x20, 0xEA, 0xBF, 0xA5, 0x4D, 0x9C, 0x7C, 0x9E, 0xD0, 0xA4, 0x0D, 0x1D, 0x85, 0xF1, 0x03, 0xBA, 0xA0, 0xF7, 0x37, 0x96, 0x0E, 0x05, 0x4C, 0xCD, 0x96, 0x9E, 0x7F, 0xF2, 0xE9, 0xE5, 0xA2, 0x7F, 0xED, 0x32, 0x13, 0x24, 0x1F, 0x60, 0x93, 0x0F, 0x25, 0x4D, 0x96, 0x9B, 0x4C, 0x19, 0xE1, 0xA8, 0x20, 0x41, 0x27, 0xE5, 0x1C, 0x92, 0x30, 0x93, 0x15, 0x0D, 0xD8, 0xCB, 0xAC, 0x25, 0xE1, 0x60, 0xE2, 0x4D, 0x1E},
+ []uint{36, 31, 43, 61, 45, 54, 48, 21, 50, 49, 44, 30, 7, 12, 26, 30, 62, 63, 60, 28},
+ []uint64{0x6918CA1F7, 0x36C80546, 0x11F242E3252, 0x1F970F7FD3E2D375, 0x12DA4A862E93, 0x16AC18455CB748, 0x3AAFE953671F, 0x4F685, 0x81A3B0BE2077, 0xA83DCDE58381, 0x533365A79FF, 0x32E9E5A2, 0x3F, 0xF69, 0x2426483, 0x3B049879, 0xA9B2D369833C350, 0x204127E51C923093, 0x150DD8CBAC25E16, 0xE24D1E},
+ },
+ {
+ []byte{0x06, 0x15, 0x43, 0xBF, 0x63, 0x7B, 0xFD, 0x1D, 0xED, 0xB3, 0x50, 0x4E, 0x2F, 0x27, 0x4D, 0x97, 0xD2, 0x0D, 0x47, 0x39, 0xD1, 0x16, 0x90, 0x26, 0xEC, 0xC6, 0x5D, 0x6C, 0xA5, 0x99, 0x92, 0x02, 0xD7, 0x1D, 0x35, 0x00, 0x4A, 0xE0, 0xFF, 0xE5, 0xEC, 0x16, 0x13, 0x59, 0xB3, 0x05, 0xE9, 0x4D, 0xD5, 0x7D, 0x24, 0x81, 0x14, 0x2C, 0xF4, 0xF7, 0xBD, 0xD0, 0x19, 0xFB, 0x51, 0xE9, 0x9E, 0x54, 0x17, 0x84, 0x9E, 0x39, 0x23, 0x1E, 0xFC, 0x9B, 0xC1, 0xF2, 0x75, 0xA1, 0xC6, 0xFC, 0x3D, 0xEA, 0xB4, 0xA0, 0x64, 0xA0, 0xE0, 0x43, 0xD6, 0x66, 0xF7, 0x77, 0x0B, 0xF0, 0x1E, 0x66, 0x6B, 0x7B, 0xAD, 0xCA, 0xDB, 0xEC},
+ []uint{39, 11, 11, 10, 48, 32, 20, 46, 26, 16, 25, 24, 37, 16, 47, 63, 18, 9, 51, 38, 56, 63, 61, 32, 1},
+ []uint64{0x30AA1DFB1, 0x5EF, 0x7A3, 0x2F6, 0xD9A8271793A6, 0xCBE906A3, 0x9CE88, 0x2D204DD98CBA, 0x3652CCC, 0x9016, 0x171D350, 0x4AE0F, 0x1FCBD82C26, 0xB366, 0x5E94DD57D24, 0x408A167A7BDEE80C, 0x3F6A3, 0x1A6, 0x3CA82F093C724, 0x18F7E4DE0F, 0x93AD0E37E1EF55, 0x52819283810F599B, 0x1BBB85F80F3335BD, 0xD6E56DF6, 0x00},
+ },
+ {
+ []byte{0xA3, 0x34, 0x99, 0x5A, 0xA7, 0x43, 0xDE, 0x9D, 0x0D, 0xB0, 0x07, 0x3A, 0x06, 0x10, 0x48, 0x4F, 0x9D, 0x6E, 0xA1, 0x12, 0xBE, 0x3E, 0xBE, 0x16, 0x5C, 0x0D, 0xC9, 0x30, 0x78, 0x71, 0x44, 0x0F, 0xC1, 0xB5, 0x54, 0x00, 0xEE, 0xEB, 0x28, 0x81, 0x2C, 0xF9, 0x16, 0xEA, 0xA6, 0x31, 0x28, 0xC0, 0x08, 0xDD, 0x33, 0x89, 0x6B, 0x58, 0x2F, 0x6A, 0x73, 0xA6, 0xED, 0xDD, 0xFA, 0x6D, 0xAE, 0x45, 0xA4, 0xE1, 0x2B, 0xD3, 0xDA, 0xF1, 0x1F, 0x4A, 0x89, 0x03, 0xD4, 0x9A, 0xF1, 0x0C, 0x9B, 0x01, 0xF3, 0x67, 0x87, 0x64, 0x93, 0x21, 0x2C, 0xC7, 0x84, 0x3D, 0xBE, 0x07, 0x6B, 0x2B, 0xD2, 0x87, 0x5B, 0xAB, 0x1E, 0x2A},
+ []uint{17, 5, 3, 47, 17, 35, 37, 43, 52, 22, 45, 63, 37, 55, 37, 16, 12, 32, 12, 13, 2, 49, 3, 55, 5, 37, 15, 33, 1},
+ []uint64{0x14669, 0x06, 0x02, 0x5AA743DE9D0D, 0x1600E, 0x3A0610484, 0x1F3ADD4225, 0x3E3EBE165C0, 0xDC9307871440F, 0x306D55, 0x777594409, 0x33E45BAA98C4A300, 0x46E99C4B5, 0x560BDA9CE9BB77, 0xFD36D722D, 0x2709, 0x5E9, 0xED788FA5, 0x448, 0x3D4, 0x02, 0xD78864D80F9B, 0x01, 0x70EC92642598F0, 0x10, 0x1EDF03B595, 0x74A1, 0x1ADD58F15, 0x00},
+ },
+ {
+ []byte{0xC2, 0x1C, 0x29, 0x23, 0xD2, 0x85, 0x5C, 0x44, 0xDD, 0x85, 0xEB, 0xB0, 0x7D, 0x6B, 0x97, 0x2B, 0x4A, 0x92, 0x13, 0xDF, 0x85, 0x7B, 0x3F, 0xF1, 0x81, 0xFD, 0x59, 0xC5, 0x6B, 0x34, 0xE8, 0x98, 0xFB, 0x49, 0x38, 0x07, 0x6B, 0xE7, 0x0C, 0x2B, 0x48, 0x23, 0x87, 0x36, 0x1E, 0x2A, 0x00, 0x39, 0x0E, 0x01, 0x9C, 0x34, 0x67, 0x8D, 0x62, 0x2F, 0xD3, 0x59, 0x80, 0x20, 0x14, 0xB1, 0xDF, 0xE0, 0xA9, 0xF3, 0x05, 0x8D, 0xFB, 0x1F, 0xD2, 0xE5, 0x43, 0xEA, 0xEB, 0xE0, 0xF3, 0x78, 0x15, 0x16, 0x34, 0x1A, 0xD7, 0x05, 0xB3, 0x66, 0xC1, 0xB1, 0x7A, 0x98, 0xFB, 0x9C, 0x88, 0x1F, 0xD4, 0xD4, 0xEF, 0x03, 0x43, 0xFA},
+ []uint{54, 24, 30, 28, 48, 31, 42, 39, 14, 8, 55, 63, 17, 57, 64, 10, 62, 60, 10, 41, 31, 12},
+ []uint64{0x30870A48F4A157, 0x113761, 0x1EBB07D6, 0xB972B4A, 0x9213DF857B3F, 0x78C0FEAC, 0x38AD669D131, 0x7B4938076B, 0x39C3, 0x0A, 0x690470E6C3C540, 0x390E019C34678D6, 0x45FA, 0xD66008052C77F8, 0x2A7CC1637EC7F4B9, 0x143, 0x3ABAF83CDE05458D, 0x6B5C16CD9B06C5, 0x3A9, 0x11F739103FA, 0x4D4EF034, 0x3FA},
+ },
+ {
+ []byte{0x2E, 0xB7, 0x5F, 0x66, 0x0C, 0xEE, 0x9F, 0x22, 0x62, 0xEE, 0x89, 0x47, 0x18, 0x75, 0xC2, 0x9C, 0x4B, 0xC0, 0x5A, 0xB1, 0x11, 0x1F, 0x57, 0xA4, 0x68, 0xF4, 0xA9, 0xF4, 0x0A, 0x52, 0x86, 0xA5, 0x4B, 0x56, 0xBF, 0xC0, 0x2F, 0x16, 0x31, 0x62, 0xA2, 0x78, 0xD1, 0x9D, 0xE9, 0x0F, 0x2D, 0x40, 0xC5, 0xA7, 0x3C, 0x6C, 0x53, 0x8A, 0xBF, 0xD2, 0x16, 0x78, 0xDB, 0x22, 0xD3, 0x19, 0x69, 0x17, 0x9D, 0x81, 0x43, 0x98, 0x3A, 0x82, 0x93, 0x84, 0xFF, 0x4B, 0xA0, 0x26, 0xB0, 0x5C, 0xC3, 0x72, 0xA5, 0x7C, 0xDE, 0xC8, 0xD5, 0x2E, 0x6F, 0x80, 0x75, 0x14, 0xA5, 0xAB, 0x96, 0xEE, 0x60, 0x94, 0x0D, 0x42, 0xB9, 0x62},
+ []uint{49, 25, 55, 41, 56, 18, 46, 16, 29, 17, 38, 39, 23, 18, 12, 34, 45, 9, 4, 48, 28, 59, 9, 14, 15, 34, 19},
+ []uint64{0x5D6EBECC19DD, 0x7C898B, 0x5D128E30EB8538, 0x12F016AC444, 0x7D5E91A3D2A7D0, 0xA528, 0x1A952D5AFF00, 0xBC58, 0x18B1513C, 0xD19D, 0x3A43CB5031, 0x34E78D8A71, 0x2BFD21, 0x19E36, 0xC8B, 0x131969179, 0x1B0287307505, 0x4E, 0x01, 0x3FD2E809AC17, 0x30DCA95, 0x79BD91AA5CDF00E, 0x145, 0xA5A, 0x5CB7, 0x1CC1281A8, 0x2B962},
+ },
+ {
+ []byte{0x11, 0x9E, 0xE6, 0x8D, 0x03, 0x9F, 0x19, 0x2F, 0x7C, 0x53, 0xA3, 0xA6, 0x8F, 0x6C, 0xA2, 0xF4, 0x0E, 0xE2, 0x21, 0x84, 0x09, 0xDB, 0x3C, 0xDF, 0x61, 0xEC, 0xCE, 0x30, 0xF0, 0x0B, 0x4E, 0x47, 0x97, 0x26, 0xE2, 0xE8, 0x13, 0x7A, 0x9D, 0x77, 0x17, 0x28, 0xB2, 0x5F, 0x77, 0x64, 0x25, 0x93, 0x01, 0xEB, 0x8B, 0xD9, 0x8F, 0x54, 0x49, 0x2C, 0x0B, 0x6F, 0x85, 0x9E, 0x06, 0x34, 0x26, 0x0C, 0xF1, 0x44, 0xC9, 0x5D, 0x04, 0x46, 0x92, 0x69, 0xA1, 0x16, 0xA9, 0x0D, 0x32, 0x3A, 0x88, 0x11, 0x33, 0x3B, 0xCD, 0x3F, 0x78, 0x4F, 0x0A, 0x5D, 0x55, 0x69, 0x35, 0x22, 0x2C, 0x90, 0xFD, 0xC2, 0x49, 0xF5, 0x44, 0x7D},
+ []uint{50, 55, 18, 59, 59, 49, 28, 6, 23, 35, 63, 16, 40, 13, 12, 43, 56, 7, 34, 44, 3, 18, 11, 52, 6},
+ []uint64{0x467B9A340E7C, 0x325EF8A7474D1E, 0x36517, 0x503B888610276CF, 0x1BEC3D99C61E016, 0x1391E5C9B8BA0, 0x4DEA75D, 0x31, 0x394592, 0x7DDD90964, 0x603D717B31EA8925, 0x816D, 0xF0B3C0C684, 0x1833, 0xC51, 0x192BA088D24, 0xD3422D521A6475, 0x08, 0x44CCEF34, 0xFDE13C29755, 0x02, 0x349A9, 0x8B, 0x243F70927D511, 0x3D},
+ },
+ {
+ []byte{0x6D, 0x2D, 0x02, 0x1B, 0x65, 0xC7, 0x93, 0x72, 0xA1, 0xC8, 0x00, 0xE7, 0xD6, 0xB5, 0x89, 0x88, 0x9B, 0x48, 0x4E, 0x8A, 0x7F, 0x41, 0x10, 0x12, 0x6B, 0xF5, 0x3C, 0x74, 0x9F, 0x86, 0x6F, 0x9E, 0x74, 0x0C, 0x6C, 0x80, 0x6D, 0x65, 0xBB, 0xAC, 0x9A, 0xAF, 0x74, 0x6E, 0x28, 0x07, 0x2D, 0xCD, 0x12, 0x07, 0xEE, 0x47, 0x97, 0xC0, 0xF8, 0x85, 0xBC, 0x6C, 0x00, 0xE6, 0x03, 0x07, 0x19, 0xB2, 0xE0, 0xC0, 0x76, 0x24, 0xB8, 0xD0, 0x98, 0x5B, 0xD3, 0xBE, 0x06, 0x6C, 0x9C, 0xF2, 0x64, 0xC2, 0xAC, 0x9D, 0xE2, 0x58, 0x76, 0xF0, 0x2F, 0x1D, 0xA8, 0x92, 0xDA, 0xB8, 0x54, 0xEE, 0xC9, 0xB2, 0x6F, 0xE2, 0xC2, 0x3A},
+ []uint{49, 35, 28, 50, 45, 11, 8, 11, 41, 57, 52, 4, 57, 7, 55, 27, 27, 30, 12, 10, 64, 32, 58, 10, 20},
+ []uint64{0xDA5A0436CB8F, 0x1372A1C80, 0xE7D6B5, 0x226226D213A29, 0x1FA0880935FA, 0x4F1, 0xD2, 0x3F0, 0x19BE79D031B, 0x4036B2DDD64D57, 0xBA37140396E68, 0x09, 0x7EE4797C0F885, 0x5E, 0x1B003980C1C66C, 0x5C180EC, 0x24B8D09, 0x216F4EF8, 0x19B, 0x9C, 0xF264C2AC9DE25876, 0xF02F1DA8, 0x24B6AE153BB26C9, 0x2FE, 0x2C23A},
+ },
+ {
+ []byte{0xF6, 0x50, 0x44, 0x6B, 0xE9, 0x59, 0x96, 0x1E, 0x48, 0x15, 0x9A, 0x63, 0x62, 0xDC, 0x04, 0x5E, 0x86, 0xE3, 0xCA, 0x7A, 0x47, 0x38, 0x1C, 0xB8, 0xD0, 0x0F, 0x4D, 0x0B, 0x7C, 0x4D, 0xB8, 0xE7, 0xAB, 0xD2, 0x11, 0x03, 0x13, 0x90, 0xD1, 0x08, 0x50, 0xD0, 0xC9, 0xAE, 0xBD, 0x67, 0xB2, 0x3B, 0xDE, 0xED, 0x7B, 0x79, 0x0F, 0x23, 0xE2, 0x89, 0x33, 0x7E, 0xE9, 0x07, 0xE1, 0x24, 0xDC, 0xAB, 0x49, 0xDE, 0x26, 0xFC, 0xA1, 0xE3, 0x9B, 0x6C, 0x16, 0x5E, 0x60, 0xEA, 0xFF, 0x67, 0x56, 0x9B, 0xF3, 0x88, 0xCC, 0x57, 0x56, 0xCB, 0x76, 0x25, 0xDA, 0xB5, 0x9C, 0xE8, 0x3D, 0xB7, 0x79, 0xED, 0xF5, 0xB4, 0x99, 0xB4},
+ []uint{44, 12, 8, 57, 32, 29, 32, 28, 18, 40, 8, 58, 60, 59, 64, 50, 46, 4, 46, 59, 46},
+ []uint64{0xF650446BE95, 0x996, 0x1E, 0x902B34C6C5B808, 0xBD0DC794, 0x1E91CE07, 0x2E3403D3, 0x42DF136, 0x38E7A, 0xBD21103139, 0x0D, 0x421434326BAF59, 0xEC8EF7BB5EDE43C, 0x47C51266FDD20FC, 0x249B95693BC4DF94, 0xF1CDB60B2F30, 0x1D5FECEAD37E, 0x07, 0x4662BAB65BB, 0x976AD673A0F6DD, 0x39EDF5B499B4},
+ },
+ {
+ []byte{0xB0, 0x15, 0x5C, 0x01, 0xE3, 0x0E, 0x1A, 0xB6, 0x97, 0x04, 0x07, 0x63, 0xBB, 0x29, 0x2D, 0xB7, 0x80, 0xD3, 0x50, 0x42, 0x6B, 0xA3, 0xCA, 0x7C, 0x71, 0x40, 0xF2, 0xB6, 0x51, 0x89, 0x52, 0x84, 0xF1, 0x93, 0xAB, 0xAF, 0xC9, 0x9D, 0x1C, 0x3D, 0x43, 0xEC, 0xB8, 0x6F, 0xA1, 0xCE, 0xAB, 0x94, 0xF2, 0xF0, 0xF3, 0x14, 0xE9, 0x41, 0x02, 0x9B, 0xA6, 0x42, 0x83, 0xB7, 0xF6, 0x58, 0x60, 0x60, 0xDD, 0xD1, 0xC3, 0xCF, 0xCA, 0x4C, 0x74, 0xDC, 0x6D, 0xEF, 0x7F, 0x8C, 0x9F, 0xE9, 0xE4, 0x1F, 0xDF, 0xCD, 0x59, 0xAC, 0x70, 0x43, 0xE0, 0xF9, 0x5E, 0xB6, 0x8D, 0x10, 0x5F, 0xE0, 0x4B, 0x85, 0xD8, 0xCF, 0x59, 0xE3},
+ []uint{55, 6, 54, 27, 46, 46, 43, 11, 7, 18, 16, 23, 23, 60, 12, 9, 54, 61, 39, 31, 54, 34, 40, 31},
+ []uint64{0x580AAE00F1870D, 0x16, 0x34B8203B1DD949, 0x36DE034, 0x350426BA3CA7, 0x31C503CAD946, 0x12A509E3275, 0x3AF, 0x64, 0x33A38, 0x7A87, 0x6CB86F, 0x50E755, 0xCA7978798A74A08, 0x14D, 0x1A6, 0x10A0EDFD961818, 0x6EE8E1E7E5263A6, 0x71B7BDFE32, 0x3FD3C83F, 0x2FE6ACD63821F0, 0x1F2BD6D1A, 0x20BFC0970B, 0x58CF59E3},
+ },
+ {
+ []byte{0x7F, 0x0D, 0xFB, 0x8B, 0x93, 0x2C, 0x51, 0xC3, 0xAE, 0x2F, 0xBE, 0xD2, 0xAD, 0xFE, 0x95, 0x3F, 0xEB, 0x41, 0xF1, 0x59, 0xDD, 0xBA, 0x1F, 0x31, 0xC1, 0x5C, 0x82, 0x78, 0x93, 0x3A, 0x53, 0x99, 0x29, 0x1F, 0x3E, 0x5B, 0xB5, 0x69, 0x25, 0x22, 0x34, 0xF3, 0x7C, 0x3A, 0xA8, 0xB6, 0xE4, 0xE3, 0x5E, 0xD5, 0x9D, 0xFB, 0x69, 0x49, 0xD0, 0x9F, 0x01, 0x4C, 0x03, 0x88, 0xD2, 0x82, 0x6E, 0xC7, 0x85, 0x35, 0x4D, 0xE7, 0x19, 0xA6, 0xF8, 0x1D, 0x3D, 0xDD, 0xC7, 0xE1, 0x89, 0x83, 0x69, 0xD9, 0xA3, 0x30, 0x25, 0x42, 0x95, 0x6E, 0x02, 0xFE, 0xC9, 0xDC, 0x6E, 0xD8, 0x58, 0xBB, 0xB6, 0x61, 0x48, 0xB9, 0x6D, 0xF8},
+ []uint{57, 11, 41, 47, 48, 3, 18, 37, 2, 23, 46, 10, 41, 43, 30, 51, 30, 22, 54, 24, 59, 11, 30, 21, 6, 34, 1},
+ []uint64{0xFE1BF7172658A3, 0x43A, 0x1C5F7DA55BF, 0x6953FEB41F15, 0x9DDBA1F31C15, 0x06, 0x104F1, 0x4CE94E64A, 0x01, 0xF9F2D, 0x36AD24A4469E, 0x1BE, 0x3AA8B6E4E3, 0x2F6ACEFDB4A, 0x13A13E02, 0x4C0388D2826EC, 0x1E14D537, 0x2719A6, 0x3E074F7771F862, 0x60DA76, 0x346604A852ADC05, 0x7EC, 0x2771BB61, 0xC5DDB, 0x0C, 0xA45CB6FC, 0x00},
+ },
+ {
+ []byte{0xA8, 0x79, 0x2E, 0x69, 0x7C, 0xA9, 0x38, 0x1C, 0xBB, 0x72, 0x13, 0x55, 0xA9, 0x2B, 0xC6, 0xCD, 0xB9, 0x05, 0xAA, 0x90, 0xE3, 0x86, 0x2A, 0xB2, 0xD4, 0x18, 0x0C, 0xC0, 0x79, 0x2E, 0xFB, 0x29, 0x9B, 0x65, 0xA7, 0xB5, 0x06, 0x46, 0xD4, 0x1C, 0x7C, 0x4D, 0xDA, 0x29, 0x68, 0x83, 0xA6, 0x66, 0xFE, 0xA8, 0x96, 0x52, 0xAF, 0x88, 0x38, 0x25, 0x15, 0x51, 0xE0, 0x46, 0x29, 0x70, 0x7D, 0x74, 0xC9, 0xA2, 0xDD, 0x9C, 0xEA, 0x0D, 0x42, 0xFA, 0x50, 0x6A, 0x52, 0x77, 0x24, 0xC8, 0x37, 0x40, 0x45, 0x01, 0xEC, 0x9C, 0xDE, 0x91, 0x94, 0x23, 0xBD, 0x0A, 0xFA, 0x68, 0x39, 0xF3, 0x4F, 0xAD, 0x4E, 0xF4, 0xEB, 0x35},
+ []uint{16, 23, 38, 47, 6, 47, 2, 15, 21, 1, 13, 37, 17, 45, 6, 40, 31, 56, 59, 25, 27, 12, 14, 60, 64, 35, 10, 33},
+ []uint64{0xA879, 0x1734BE, 0x152703976E, 0x21355A92BC6C, 0x36, 0x720B5521C70C, 0x01, 0x2ACB, 0xA0C06, 0x00, 0x180F, 0x4BBECA66D, 0x12D3D, 0x150646D41C7C, 0x13, 0x768A5A20E9, 0x4CDFD512, 0xCA55F10704A2AA, 0x1E04629707D74C9, 0x145BB39, 0x6A0D42F, 0xA50, 0x1A94, 0x9DC9320DD011407, 0xB2737A46508EF42B, 0x74D073E69, 0x3D6, 0x14EF4EB35},
+ },
+ {
+ []byte{0x79, 0xD5, 0x86, 0x52, 0x20, 0xE8, 0xC2, 0x30, 0x48, 0xBC, 0x55, 0xC3, 0x16, 0x7C, 0xAA, 0xED, 0x94, 0xB2, 0xEC, 0x72, 0xB6, 0x37, 0x2D, 0xDC, 0xC5, 0x32, 0xD7, 0x37, 0xEC, 0x9F, 0xBF, 0x05, 0x83, 0x87, 0x82, 0x02, 0xE9, 0xDF, 0x9A, 0x27, 0x20, 0x18, 0xC4, 0x63, 0x9B, 0x2B, 0x74, 0xFB, 0xC9, 0xBD, 0xE2, 0xF0, 0xD6, 0xB7, 0x88, 0x28, 0x2B, 0x8F, 0xD1, 0xE5, 0xE0, 0xFC, 0x54, 0x53, 0xC6, 0x3C, 0xD5, 0xC6, 0xCC, 0x18, 0x12, 0xDC, 0xAB, 0x57, 0x56, 0x3A, 0xCC, 0x3A, 0x42, 0x65, 0x30, 0x02, 0xB5, 0x17, 0x69, 0x18, 0x86, 0xB0, 0xC0, 0xE8, 0x65, 0x96, 0xBB, 0x24, 0x42, 0xCA, 0x60, 0x74, 0x3E, 0x4E},
+ []uint{49, 12, 22, 14, 60, 8, 49, 19, 64, 29, 5, 37, 17, 56, 40, 3, 4, 19, 29, 45, 6, 51, 14, 10, 53, 48, 37},
+ []uint64{0xF3AB0CA441D1, 0x846, 0x245E2, 0x2B86, 0x2CF955DB2965D8E, 0x56, 0x18DCB77314CB5, 0x66FD9, 0x3F7E0B070F0405D3, 0x17E689C8, 0x00, 0x18C4639B2B, 0xE9F7, 0x937BC5E1AD6F10, 0x50571FA3CB, 0x06, 0x00, 0x7E2A2, 0x13C63CD5, 0x18D983025B95, 0x1A, 0x5D58EB30E9099, 0x1300, 0xAD, 0x8BB48C4358607, 0x432CB5D92216, 0xA60743E4E},
+ },
+ {
+ []byte{0x1D, 0x25, 0xA6, 0x20, 0x3A, 0x6C, 0x00, 0xE9, 0xD1, 0x02, 0xD0, 0xA1, 0xB6, 0xEF, 0xA5, 0x89, 0x34, 0xCC, 0x79, 0x82, 0x7E, 0x3A, 0x46, 0x57, 0xF5, 0x83, 0x6E, 0xAE, 0xF2, 0x43, 0x25, 0xA5, 0xD5, 0xF0, 0x9B, 0x8E, 0xDD, 0x0F, 0xCC, 0x8E, 0x0C, 0xD7, 0xB1, 0xC3, 0x56, 0x9F, 0xA0, 0x2A, 0x9D, 0x0C, 0x37, 0xD1, 0xBD, 0x13, 0x67, 0x31, 0xD4, 0x84, 0xD3, 0xE9, 0xCE, 0xB2, 0x34, 0xDB, 0xFC, 0x31, 0x75, 0xCD, 0x70, 0x08, 0x4C, 0x71, 0x75, 0xDD, 0x8F, 0x3F, 0xD5, 0xFA, 0xC3, 0x24, 0xE8, 0xC0, 0x10, 0x9B, 0x7C, 0xF9, 0xCA, 0xE9, 0x54, 0x21, 0xD8, 0xE3, 0x8D, 0x31, 0xA3, 0x39, 0xA5, 0xC4, 0xF3, 0xFC},
+ []uint{32, 13, 52, 46, 22, 7, 13, 37, 50, 64, 63, 60, 52, 42, 57, 35, 35, 54, 35, 31},
+ []uint64{0x1D25A620, 0x74D, 0x801D3A205A143, 0x1B77D2C49A66, 0xF304F, 0x63, 0x148C, 0x15FD60DBAB, 0x2F24325A5D5F0, 0x9B8EDD0FCC8E0CD7, 0x58E1AB4FD0154E86, 0x1BE8DE89B398EA4, 0x269F4E7591A6D, 0x3F862EB9AE0, 0x2131C5D7763CFF, 0x2BF58649D, 0xC0109B7C, 0x3E72BA55087638, 0x71A634673, 0x25C4F3FC},
+ },
+ {
+ []byte{0x68, 0x5A, 0x69, 0x38, 0xFD, 0x40, 0x54, 0xB3, 0x83, 0x36, 0x19, 0x7E, 0x49, 0x98, 0x71, 0xA3, 0x2A, 0x61, 0xF7, 0xE7, 0x8A, 0x7E, 0x6B, 0x1A, 0xB8, 0x98, 0x47, 0x80, 0x1A, 0x45, 0x10, 0xDC, 0xD7, 0x19, 0x89, 0xBF, 0xF0, 0x6A, 0x58, 0xFF, 0x62, 0xE4, 0xEC, 0x13, 0x4C, 0x50, 0x88, 0xFA, 0xFC, 0xA6, 0x12, 0xA6, 0xB3, 0xA4, 0xDB, 0x1E, 0x4C, 0xA4, 0x6D, 0x6B, 0xA2, 0xE1, 0xB7, 0x38, 0x47, 0x98, 0x64, 0xF9, 0xBD, 0xC2, 0x52, 0xB9, 0x85, 0x5A, 0xAA, 0x08, 0x67, 0xC9, 0xA6, 0x10, 0x6C, 0x9F, 0xB1, 0x85, 0xAB, 0x93, 0x8E, 0x27, 0x9E, 0x5A, 0xD8, 0x4B, 0xAB, 0x1D, 0x07, 0x24, 0x5A, 0x92, 0xE8, 0xFE},
+ []uint{53, 49, 47, 35, 53, 37, 62, 62, 2, 44, 23, 43, 10, 31, 49, 39, 56, 4, 58, 43},
+ []uint64{0xD0B4D271FA80A, 0x12CE0CD865F92, 0x330E34654C3E, 0x7E78A7E6B, 0x3571308F00348, 0x1443735C66, 0x9BFF06A58FF62E4, 0x3B04D314223EBF29, 0x02, 0x12A6B3A4DB1, 0x726523, 0x35AE8B86DCE, 0x47, 0x4C327CDE, 0x1C252B9855AAA, 0x433E4D308, 0x364FD8C2D5C9C7, 0x01, 0xF3CB5B097563A0, 0x7245A92E8FE},
+ },
+ {
+ []byte{0x81, 0xB5, 0xA2, 0x65, 0x98, 0x2C, 0x6B, 0x6B, 0xC7, 0x8F, 0x17, 0x8A, 0xE9, 0x66, 0xF9, 0x70, 0x5D, 0xCE, 0x2F, 0x35, 0xC3, 0xB7, 0xEC, 0xB8, 0x3F, 0xA1, 0xB8, 0x6F, 0x08, 0x31, 0xAB, 0x93, 0x9E, 0x7C, 0xFB, 0x43, 0x1C, 0xA4, 0xB6, 0xD1, 0x89, 0xD3, 0x4F, 0xD4, 0x2A, 0x89, 0x72, 0x13, 0x50, 0xB9, 0x02, 0xC7, 0x6A, 0x98, 0xE0, 0x3F, 0x75, 0x33, 0x61, 0x36, 0x8F, 0x7B, 0xC7, 0x8F, 0x7F, 0x78, 0x21, 0xC1, 0xD1, 0x73, 0x7D, 0xCE, 0x8C, 0xD6, 0xB3, 0x20, 0x9C, 0xAF, 0x5A, 0x57, 0x8B, 0xE5, 0xC6, 0xA4, 0xCA, 0x76, 0x1E, 0x50, 0x20, 0x43, 0x87, 0xE4, 0xCE, 0x0F, 0x89, 0x21, 0x64, 0x65, 0x9B, 0xD3},
+ []uint{1, 15, 30, 2, 9, 48, 40, 45, 20, 27, 29, 1, 13, 35, 47, 59, 24, 38, 50, 39, 37, 8, 54, 46, 14, 58, 11},
+ []uint64{0x01, 0x1B5, 0x2899660B, 0x00, 0xD6, 0xD78F1E2F15D2, 0xCDF2E0BB9C, 0xBCD70EDFB2E, 0xFE86, 0x70DE106, 0x6AE4E79, 0x01, 0x1CFB, 0x218E525B6, 0x46274D3F50AA, 0x12E426A172058ED, 0x531C07, 0x3BA99B09B4, 0x1EF78F1EFEF04, 0x1C1D1737DC, 0x1D19AD6641, 0x39, 0x17AD2BC5F2E352, 0x194EC3CA0408, 0x1C3F, 0x99C1F1242C8CB3, 0x3D3},
+ },
+ {
+ []byte{0x71, 0xF3, 0xAA, 0x6E, 0x84, 0xDF, 0xE6, 0x77, 0xA6, 0xC2, 0xAE, 0x13, 0x8C, 0x9E, 0xDF, 0xFA, 0x68, 0x97, 0x18, 0x10, 0x2D, 0x29, 0xE9, 0x8A, 0xBF, 0xA3, 0xB6, 0x34, 0x93, 0xA0, 0x81, 0xE6, 0xBB, 0xB2, 0x2B, 0xCC, 0x6C, 0x2E, 0xD2, 0xD0, 0x97, 0xB8, 0x7B, 0x41, 0x3D, 0x11, 0xFB, 0xFC, 0xE0, 0xE3, 0x5B, 0x75, 0xE4, 0x6A, 0x28, 0x88, 0x0A, 0x2D, 0x41, 0x6B, 0x00, 0xE3, 0xB8, 0xA1, 0x98, 0x45, 0x63, 0xD1, 0x89, 0xF1, 0xDD, 0xE5, 0xAB, 0xB8, 0x07, 0xA1, 0x7A, 0xDF, 0xA6, 0xF4, 0x89, 0x6D, 0x41, 0x90, 0xA2, 0x3B, 0x79, 0x07, 0xA6, 0xFE, 0xB5, 0x19, 0x32, 0x0D, 0x7E, 0x8F, 0x37, 0x49, 0xB1, 0x1F},
+ []uint{18, 39, 32, 4, 63, 43, 56, 45, 45, 5, 15, 29, 6, 33, 52, 33, 44, 44, 21, 32, 57, 45, 23, 16},
+ []uint64{0x1C7CE, 0x54DD09BFCC, 0xEF4D855C, 0x02, 0x38C9EDFFA6897181, 0x1694F4C55F, 0xD1DB1A49D040F3, 0xBBB22BCC6C2, 0x1DA5A12F70F6, 0x10, 0x27A2, 0x7EFF383, 0x23, 0xB6EBC8D4, 0x5110145A82D60, 0x38EE2866, 0x1158F4627C7, 0x7796AEE01E8, 0xBD6FD, 0x37A44B6A, 0x190A23B7907A6F, 0x1D6A32641AFD, 0xF3749, 0xB11F},
+ },
+ {
+ []byte{0xAC, 0x14, 0xB0, 0x1B, 0x9B, 0xF6, 0x27, 0xD0, 0xB0, 0xB4, 0x78, 0xD8, 0x72, 0x2F, 0x7B, 0x35, 0x27, 0x93, 0xD7, 0x03, 0xBE, 0x3D, 0x08, 0x38, 0xA4, 0x4F, 0x77, 0xC6, 0x93, 0x8C, 0xDF, 0x54, 0x7B, 0x25, 0x14, 0xDB, 0xF4, 0x3A, 0x1B, 0xB0, 0x20, 0x0C, 0x7A, 0x40, 0x15, 0xE4, 0xCE, 0x72, 0x9E, 0x50, 0x05, 0x85, 0xFE, 0x5A, 0xDA, 0x51, 0xC1, 0x10, 0x35, 0xB6, 0x93, 0x7D, 0xE1, 0x29, 0x8A, 0xA1, 0x64, 0xCB, 0xD7, 0x43, 0x53, 0x6F, 0x1A, 0x31, 0x83, 0x1E, 0x90, 0xFF, 0x5D, 0x99, 0xF8, 0xF1, 0xB4, 0xBD, 0x91, 0xEF, 0xF3, 0xB7, 0x70, 0x71, 0x1D, 0x09, 0x4B, 0x8A, 0x94, 0x47, 0x86, 0xDF, 0xB9, 0x73},
+ []uint{63, 40, 4, 14, 10, 41, 30, 19, 11, 22, 20, 18, 17, 26, 63, 12, 39, 8, 12, 7, 23, 64, 2, 57, 48, 5, 26, 18, 31, 29, 21},
+ []uint64{0x560A580DCDFB13E8, 0x585A3C6C39, 0x01, 0x1EF6, 0x1A9, 0x793D703BE3, 0x3420E291, 0x1EEF8, 0x693, 0x2337D5, 0x1EC94, 0x14DBF, 0x8743, 0x1D81006, 0x1E900579339CA794, 0x16, 0xBFCB5B4A3, 0x82, 0x206, 0x5B, 0x349BEF, 0x94C550B265EBA1A, 0x02, 0xDBC68C60C7A43F, 0xD7667E3C6D2F, 0x0C, 0x23DFE76, 0x3B838, 0x474252E2, 0x14A23C36, 0x1FB973},
+ },
+ {
+ []byte{0xE4, 0x50, 0xCC, 0x46, 0xE5, 0x6C, 0xB4, 0x5E, 0x7D, 0x27, 0x6A, 0x12, 0x75, 0x27, 0x71, 0xB2, 0x5F, 0xCD, 0x62, 0x8E, 0x39, 0x4C, 0x93, 0xAB, 0x74, 0x84, 0x7D, 0x73, 0x72, 0x69, 0x2B, 0x3E, 0x09, 0x98, 0x75, 0xCE, 0xEA, 0xCE, 0x41, 0x90, 0x1B, 0x5E, 0x43, 0x77, 0x9F, 0x03, 0x45, 0xD5, 0x5C, 0xE2, 0xED, 0x27, 0xF9, 0x3C, 0x74, 0x7B, 0x43, 0x46, 0x74, 0x48, 0xBA, 0x17, 0x38, 0xD5, 0x20, 0xE5, 0xA0, 0xF4, 0xF6, 0xF2, 0xDD, 0x35, 0x11, 0xDC, 0x2C, 0x05, 0x24, 0xF9, 0x32, 0x87, 0xF2, 0x46, 0x5C, 0x38, 0x5F, 0x30, 0xD5, 0xE5, 0xCA, 0x7B, 0xB2, 0x84, 0x2B, 0x52, 0x79, 0x1E, 0xA2, 0xA7, 0xF2, 0xE5},
+ []uint{36, 51, 25, 30, 33, 48, 1, 40, 47, 24, 52, 35, 50, 19, 46, 35, 49, 42, 43, 25, 3, 46, 20},
+ []uint64{0xE450CC46E, 0x2B65A2F3E93B5, 0x127527, 0x1C6C97F3, 0xB1471CA6, 0x49D5BA423EB9, 0x01, 0x72692B3E09, 0x4C3AE7756720, 0xC80DAF, 0x21BBCF81A2EAA, 0x738BB49FE, 0x13C747B434674, 0x245D0, 0x2E71AA41CB41, 0x74F6F2DD3, 0xA23B8580A49F, 0x9943F9232E, 0xE17CC35797, 0x53DD94, 0x01, 0x2B52791EA2A, 0x7F2E5},
+ },
+ {
+ []byte{0x62, 0x1F, 0x77, 0x6B, 0x70, 0x29, 0x95, 0x1E, 0xE8, 0xF4, 0xFB, 0x70, 0x7C, 0x70, 0xB6, 0x51, 0xF6, 0xD5, 0xD8, 0x16, 0x6D, 0xB0, 0x7D, 0x7F, 0xE3, 0x3A, 0x1C, 0x01, 0x3C, 0x72, 0xD5, 0x19, 0x42, 0x22, 0xE9, 0xCB, 0x6E, 0xF5, 0x4F, 0x63, 0xAA, 0x74, 0xDA, 0x86, 0x06, 0xB0, 0x0E, 0x2B, 0xF1, 0xD8, 0x12, 0x3D, 0x78, 0xCD, 0x60, 0x4F, 0xE4, 0x24, 0x18, 0xE9, 0xB2, 0x8A, 0xAC, 0xB4, 0x95, 0x53, 0x1D, 0x31, 0xDF, 0x2C, 0x24, 0x59, 0x32, 0x26, 0xFC, 0xDE, 0x18, 0x5A, 0x10, 0x25, 0x66, 0xDF, 0x5D, 0xFB, 0x4F, 0xC6, 0x40, 0xBC, 0x81, 0x51, 0xB1, 0xC5, 0xC7, 0xED, 0x68, 0xEF, 0xEF, 0x03, 0xD1, 0x3B},
+ []uint{43, 47, 64, 7, 19, 26, 16, 29, 30, 10, 17, 28, 35, 31, 49, 46, 25, 43, 18, 14, 24, 58, 17, 2, 22, 22, 18, 40},
+ []uint64{0x310FBBB5B81, 0x26547BA3D3ED, 0xC1F1C2D947DB5760, 0x2C, 0x6DB07, 0x35FF8CE, 0x8700, 0x9E396A8, 0x328445D3, 0x25B, 0xEF54, 0xF63AA74, 0x6D4303580, 0x38AFC760, 0x91EBC66B027F, 0x84831D36515, 0xB2D255, 0x263A63BE584, 0x22C99, 0x4DF, 0x9BC30B, 0x10812B36FAEFDA7, 0x1C640, 0x02, 0x3C8151, 0x2C7171, 0x3ED68, 0xEFEF03D13B},
+ },
+ {
+ []byte{0xCD, 0x82, 0x19, 0x41, 0x84, 0x11, 0x69, 0x22, 0x42, 0x4E, 0xA2, 0x7B, 0xF6, 0x52, 0xC1, 0x02, 0x54, 0x2D, 0xFB, 0x27, 0x0E, 0x8C, 0x34, 0x0A, 0xCE, 0x0E, 0x4F, 0x05, 0x94, 0x9D, 0xF2, 0x5A, 0xCB, 0x48, 0x05, 0xA3, 0x38, 0x41, 0xDE, 0x45, 0x83, 0x4F, 0x0B, 0xBF, 0x11, 0x7A, 0x01, 0x5A, 0x30, 0x93, 0x0F, 0x18, 0x86, 0x95, 0x95, 0x7E, 0x3C, 0x73, 0xB4, 0x45, 0x5F, 0xE0, 0x3B, 0xA1, 0xCA, 0x5B, 0x6E, 0x12, 0xCE, 0xF7, 0xC1, 0x48, 0x89, 0xFA, 0x79, 0x8B, 0xD2, 0x7D, 0xCC, 0x75, 0x5C, 0xF4, 0x8D, 0x72, 0x54, 0xD5, 0xED, 0x47, 0x8E, 0x6E, 0x0E, 0x18, 0x0F, 0x1B, 0xB6, 0xA3, 0x62, 0x32, 0xB2, 0xB3},
+ []uint{43, 57, 38, 50, 12, 62, 63, 24, 14, 12, 14, 42, 6, 17, 10, 51, 53, 7, 58, 1, 4, 20, 14, 29, 35, 30, 5, 29},
+ []uint64{0x66C10CA0C20, 0x116922424EA27BF, 0x194B040950, 0x2DFB270E8C340, 0xACE, 0x393C165277C96B2, 0x6900B467083BC8B0, 0x69E177, 0x388B, 0xD00, 0x2B46, 0x49878C434A, 0x32, 0x15F8F, 0x73, 0x5A22AFF01DD0E, 0xA5B6E12CEF7C1, 0x24, 0x113F4F317A4FB98, 0x01, 0x0D, 0x573D2, 0xD72, 0xA9ABDA8, 0x78E6E0E18, 0x3C6EDA8, 0x1B, 0x232B2B3},
+ },
+ {
+ []byte{0x34, 0xFA, 0x8F, 0x98, 0x59, 0x1E, 0xE3, 0x3E, 0x39, 0xCE, 0x5F, 0x3C, 0xBB, 0xEF, 0xBB, 0xE9, 0xE2, 0xA0, 0x31, 0x73, 0x67, 0x50, 0x0C, 0xF0, 0x94, 0xCC, 0x5F, 0x23, 0xF9, 0x86, 0x9D, 0xF8, 0xBD, 0xF7, 0xB9, 0x91, 0xB7, 0x06, 0xF5, 0xE0, 0x50, 0x6C, 0x2C, 0xF9, 0xE6, 0xE8, 0x2B, 0xDC, 0xBA, 0xBC, 0x02, 0x90, 0xBF, 0xF7, 0x63, 0x91, 0xF3, 0x4D, 0xAF, 0x53, 0x8D, 0xAC, 0xAE, 0xC3, 0x44, 0x24, 0xE6, 0x90, 0xCC, 0xB0, 0x16, 0x12, 0x6E, 0x35, 0x0B, 0x77, 0x2C, 0xF1, 0xF5, 0xE3, 0xA1, 0x82, 0x58, 0x2C, 0x0E, 0x64, 0xCC, 0x98, 0x39, 0x5D, 0x92, 0x91, 0xBE, 0x50, 0xC7, 0x27, 0x0C, 0x12, 0xF4, 0x0E},
+ []uint{23, 44, 62, 40, 13, 51, 6, 42, 31, 59, 29, 37, 37, 23, 23, 41, 64, 42, 44, 8, 63, 18},
+ []uint64{0x1A7D47, 0xCC2C8F719F1, 0x339CBE7977DF77D3, 0xC54062E6CE, 0x1403, 0x1E12998BE47F3, 0x03, 0x13BF17BEF73, 0x11B706F5, 0x702836167CF3741, 0xBDCBABC, 0x5217FEEC, 0xE47CD36BD, 0x271B59, 0x2EC344, 0x49CD219960, 0x2C24DC6A16EE59E3, 0x3AF1D0C12C1, 0x60732664C1C, 0xAE, 0x64A46F9431C9C304, 0x2F40E},
+ },
+ {
+ []byte{0xA8, 0xC6, 0x63, 0x71, 0x15, 0xAF, 0x2F, 0x1D, 0x44, 0x45, 0xC8, 0xCC, 0x64, 0xED, 0x7E, 0xB7, 0xC5, 0x8A, 0xC1, 0x2A, 0xF9, 0xA0, 0x9E, 0x6B, 0xD2, 0x1E, 0xC7, 0x83, 0x6C, 0x44, 0x73, 0x04, 0x5F, 0xD8, 0x31, 0x89, 0xCF, 0xA2, 0x2C, 0xDE, 0xCF, 0x5F, 0xF3, 0xE6, 0xCF, 0x88, 0x7A, 0xE9, 0x3F, 0xD2, 0x23, 0x25, 0x9D, 0x4F, 0xF4, 0xC3, 0x39, 0xB9, 0x60, 0xCA, 0x31, 0xD2, 0xFC, 0xF3, 0xC1, 0x29, 0xC8, 0x5C, 0x05, 0x95, 0xA1, 0xB7, 0x72, 0xC9, 0x8B, 0x85, 0xFD, 0x18, 0xCB, 0x05, 0x9B, 0x11, 0xD8, 0xEA, 0xF6, 0x4E, 0xB2, 0xDA, 0x35, 0xEC, 0xDD, 0x75, 0x3E, 0xCC, 0xCE, 0x5F, 0x3A, 0xFB, 0xC3, 0x01},
+ []uint{2, 38, 8, 59, 17, 7, 23, 38, 34, 52, 45, 60, 36, 45, 22, 55, 6, 9, 26, 11, 37, 37, 19, 56, 27, 31},
+ []uint64{0x02, 0x28C6637115, 0xAF, 0x178EA222E466327, 0xD7EB, 0x3E, 0x162B04, 0x2AF9A09E6B, 0x3487B1E0D, 0xB111CC117F60C, 0xC4E7D1166F6, 0x7AFF9F367C43D74, 0x9FE91192C, 0x1D4FF4C339B9, 0x18328C, 0x3A5F9E7825390B, 0x20, 0x59, 0x1686DDC, 0x593, 0x2E17F4632, 0x182CD88EC7, 0x2BD93, 0xACB68D7B375D4F, 0x5999CBE, 0x3AFBC301},
+ },
+ {
+ []byte{0x2B, 0x17, 0x50, 0xEA, 0x8B, 0xD1, 0x09, 0x00, 0x9C, 0x2E, 0x3C, 0x07, 0x3B, 0x0D, 0xFC, 0x07, 0xAA, 0xD1, 0x55, 0x1E, 0x37, 0x40, 0xE0, 0xBB, 0xC5, 0x38, 0x40, 0x64, 0xF5, 0x3C, 0x0B, 0x0B, 0x37, 0x76, 0x43, 0xDA, 0x7F, 0x01, 0x63, 0x03, 0xA3, 0xF9, 0xD8, 0x06, 0x93, 0x4C, 0xF0, 0x01, 0xE6, 0x86, 0xAA, 0x94, 0x35, 0xD5, 0xB3, 0xA2, 0x1D, 0xB6, 0x2A, 0x40, 0x83, 0xFE, 0x63, 0x2E, 0x40, 0x81, 0x42, 0x11, 0xC4, 0x61, 0x9A, 0xAF, 0x08, 0x0D, 0x36, 0x20, 0x32, 0x67, 0xEA, 0x49, 0xF4, 0x26, 0xA5, 0x8D, 0xF4, 0xFD, 0xAC, 0x15, 0xB2, 0x5B, 0x97, 0x49, 0xC2, 0xDE, 0x1D, 0x79, 0x43, 0xD8, 0x20, 0x63},
+ []uint{58, 27, 18, 25, 4, 25, 47, 9, 22, 36, 4, 53, 13, 53, 15, 15, 2, 54, 34, 62, 62, 37, 41, 34, 50},
+ []uint64{0xAC5D43AA2F4424, 0x1385C7, 0x2039D, 0x10DFC07, 0x0A, 0x15A2AA3, 0x63740E0BBC53, 0x108, 0x327A9, 0xE05859BBB, 0x02, 0x3DA7F016303A3, 0x1F3B, 0x1A4D33C0079A, 0xD55, 0x1435, 0x03, 0x15B3A21DB62A40, 0x20FF98CB9, 0x814211C4619AAF, 0x2034D880C99FA92, 0xFA1352C6F, 0x14FDAC15B25, 0x2E5D270B7, 0x21D7943D82063},
+ },
+ {
+ []byte{0x93, 0x6A, 0xA0, 0xA2, 0xA9, 0x33, 0x42, 0x9C, 0x74, 0x54, 0x5E, 0x06, 0x0E, 0xE2, 0x05, 0x9E, 0x8F, 0xCC, 0x56, 0xBC, 0x59, 0xBD, 0xAF, 0x76, 0x71, 0x9C, 0x06, 0x88, 0x42, 0x5A, 0xBC, 0x12, 0x29, 0x1C, 0x48, 0x11, 0x96, 0xA0, 0x78, 0x15, 0x6D, 0xDE, 0x8F, 0xF4, 0xBC, 0x9D, 0xB1, 0x4B, 0xEB, 0xDC, 0x9F, 0x6B, 0x70, 0xE3, 0x77, 0x32, 0x42, 0xAE, 0x35, 0x82, 0x8A, 0xD9, 0x1E, 0x26, 0x33, 0xA2, 0x51, 0xD9, 0x2B, 0xAE, 0x07, 0xBF, 0x8B, 0x14, 0x8D, 0x53, 0xC5, 0xFF, 0xE4, 0x27, 0x9F, 0x10, 0xC3, 0x2B, 0x4B, 0x90, 0x9F, 0xB2, 0x99, 0x38, 0xA7, 0xB4, 0xD2, 0xA4, 0x4B, 0xF3, 0x5D, 0x52, 0x94, 0xD2},
+ []uint{29, 7, 49, 40, 43, 23, 4, 17, 13, 29, 59, 63, 8, 25, 2, 28, 49, 27, 50, 14, 6, 5, 22, 20, 3, 35, 32, 19, 12, 48, 19},
+ []uint64{0x126D5414, 0x2A, 0x12668538E8A8B, 0xC0C1DC40B3, 0x68FCC56BC59, 0x5ED7BB, 0x03, 0x119C0, 0xD10, 0x1096AF04, 0x4523890232D40F0, 0x156DDE8FF4BC9DB1, 0x4B, 0x1D7B93E, 0x03, 0x5B871BB, 0x13242AE35828A, 0x6C8F131, 0x2744A3B2575C0, 0x3DFC, 0x16, 0x05, 0x8D53C, 0x5FFE4, 0x01, 0x1E7C430CA, 0xD2E427EC, 0x53271, 0x4F6, 0x9A54897E6BAA, 0x294D2},
+ },
+ {
+ []byte{0x41, 0x7C, 0x00, 0xB7, 0x0A, 0x88, 0x91, 0x50, 0x11, 0x1E, 0x2D, 0xDC, 0xA6, 0xF0, 0x3D, 0xDE, 0xC4, 0x37, 0xD7, 0x61, 0x65, 0x8D, 0x2B, 0x3A, 0x94, 0xAB, 0x46, 0xC3, 0x9D, 0xD1, 0x8B, 0x38, 0x7B, 0x5F, 0x17, 0xB5, 0xFF, 0x73, 0xE1, 0xAB, 0x17, 0x34, 0x4B, 0x0F, 0x5B, 0xB7, 0x84, 0x94, 0x06, 0xB1, 0x01, 0x15, 0x57, 0x4C, 0x77, 0xBF, 0xF8, 0x31, 0x6C, 0x2D, 0xDB, 0x80, 0x94, 0x7F, 0x70, 0xF5, 0x9F, 0xB9, 0xAF, 0xEB, 0x79, 0x15, 0xD5, 0xCF, 0x69, 0x55, 0x39, 0x69, 0xF0, 0x2E, 0xEB, 0x7F, 0x98, 0x8F, 0x9D, 0x51, 0x8B, 0x5F, 0xC0, 0xD1, 0x3F, 0xAB, 0xA7, 0x6B, 0x27, 0xED, 0x5C, 0x81, 0x42, 0x87},
+ []uint{43, 57, 36, 34, 17, 2, 53, 49, 40, 39, 30, 24, 9, 35, 21, 28, 19, 53, 4, 53, 57, 53, 12, 22, 10},
+ []uint64{0x20BE005B854, 0x89150111E2DDCA, 0x6F03DDEC4, 0xDF5D8596, 0x6959, 0x03, 0xA52AD1B0E7746, 0x59C3DAF8BDAF, 0xFB9F0D58B9, 0x512C3D6EDE, 0x49406B1, 0x11557, 0x98, 0x77BFF8316, 0x185BB7, 0x128FEE, 0xF59F, 0x1735FD6F22BAB9, 0x0E, 0x1A554E5A7C0BBA, 0x1BFCC47CEA8C5AF, 0x1C0D13FABA76B2, 0x7ED, 0x172050, 0x287},
+ },
+ {
+ []byte{0x62, 0x94, 0x17, 0x81, 0xEB, 0x57, 0xC8, 0x95, 0x9F, 0x6D, 0x5E, 0xB5, 0xB7, 0x75, 0xE0, 0x67, 0xB5, 0x74, 0xBB, 0x0D, 0xCE, 0xA3, 0x1A, 0x2A, 0xC7, 0x51, 0x0E, 0x1B, 0x08, 0x9E, 0xA2, 0xFC, 0x01, 0x20, 0xBF, 0xA3, 0x6B, 0xAC, 0x4B, 0x5B, 0x25, 0x35, 0xE1, 0x2A, 0x6F, 0xD2, 0x27, 0x6C, 0x29, 0x3C, 0x8A, 0x7E, 0x1C, 0x0D, 0xCD, 0x6A, 0x0B, 0x51, 0x7F, 0x12, 0x4D, 0xE8, 0xAC, 0x16, 0x18, 0x83, 0x16, 0xFD, 0xFE, 0x01, 0xA1, 0xC7, 0xF9, 0x6A, 0xBB, 0x48, 0x76, 0x98, 0xF0, 0x09, 0xE3, 0x9A, 0x2F, 0x83, 0xDF, 0x55, 0x4D, 0x41, 0xDC, 0x6F, 0x39, 0xA4, 0xEA, 0x6D, 0x3E, 0x4D, 0xD3, 0xE7, 0x8F, 0xFB},
+ []uint{20, 19, 52, 17, 9, 10, 40, 5, 57, 24, 46, 25, 24, 11, 18, 13, 24, 39, 8, 27, 34, 11, 53, 48, 36, 44, 36, 50},
+ []uint64{0x62941, 0x3C0F5, 0xABE44ACFB6AF5, 0x15B77, 0xBC, 0x33, 0xDABA5D86E7, 0x0A, 0x634558EA21C361, 0x13D45F, 0x200905FD1B5D, 0xC4B5B2, 0x535E12, 0x537, 0x3A44E, 0x1B0A, 0x4F229F, 0x4381B9AD41, 0x6A, 0x17F124D, 0x3A2B05862, 0x62, 0x1BF7F806871FE5, 0xAAED21DA63C0, 0x278E68BE0, 0xF7D55350771, 0xBCE693A9B, 0x13E4DD3E78FFB},
+ },
+ {
+ []byte{0x6B, 0x8C, 0x0C, 0x85, 0x7A, 0x48, 0x0C, 0xBA, 0x1D, 0x28, 0x30, 0xB4, 0x23, 0xA2, 0x16, 0x85, 0x62, 0x13, 0x29, 0x59, 0x81, 0x4E, 0x23, 0xDC, 0xA7, 0xD7, 0x85, 0x14, 0x4B, 0xD8, 0x8E, 0xA7, 0xD7, 0xC2, 0x3A, 0xD2, 0x86, 0x60, 0xA0, 0xBE, 0x6A, 0x22, 0xCD, 0xF1, 0x07, 0x75, 0xD2, 0x48, 0x9A, 0xEA, 0x56, 0x3D, 0x16, 0x70, 0xEF, 0x9F, 0xF5, 0xC2, 0x94, 0x86, 0x4C, 0x21, 0x29, 0x85, 0x9A, 0x84, 0x52, 0xF4, 0x41, 0xAC, 0xC5, 0x17, 0xD9, 0x72, 0xBE, 0xBA, 0x88, 0x38, 0xC2, 0xD2, 0x7D, 0xB3, 0xC1, 0x7A, 0x93, 0x61, 0x35, 0xEF, 0x34, 0xB3, 0x92, 0xA0, 0x7A, 0x34, 0x7B, 0x4D, 0x93, 0xDE, 0x1C, 0x46},
+ []uint{61, 42, 37, 33, 39, 19, 40, 14, 62, 26, 60, 57, 36, 52, 19, 64, 51, 33, 55},
+ []uint64{0xD718190AF490197, 0x10E94185A11, 0x1A21685621, 0x652B3029, 0x623DCA7D78, 0x28A25, 0xEC4753EBE1, 0x75A, 0x14330505F351166F, 0x220EEBA, 0x49135D4AC7A2CE1, 0x1BE7FD70A521930, 0x84A6166A1, 0x14BD106B3145F, 0x32E57, 0xD75107185A4FB678, 0x17A936135EF34, 0x1672540F4, 0x347B4D93DE1C46},
+ },
+ {
+ []byte{0xC8, 0x0A, 0xF4, 0xE9, 0x19, 0x51, 0xA6, 0xEA, 0x2C, 0x73, 0xB2, 0x54, 0xCE, 0x8B, 0x7D, 0x94, 0xDC, 0xB5, 0x38, 0x27, 0x6E, 0xD0, 0x3A, 0x1E, 0xA2, 0x09, 0x63, 0x7B, 0x9E, 0x2B, 0x7F, 0x8C, 0x9E, 0x49, 0x42, 0x8A, 0x15, 0xDF, 0xF7, 0xF9, 0xDF, 0xCA, 0xE3, 0xB5, 0x3D, 0x4F, 0xE0, 0x67, 0x7C, 0xC5, 0x77, 0x59, 0x1C, 0x51, 0x28, 0xD0, 0x0A, 0xE7, 0x4A, 0x14, 0xE5, 0x49, 0xF9, 0xA1, 0x49, 0x08, 0x3B, 0xE7, 0x3D, 0xC2, 0xB9, 0x95, 0x06, 0x8A, 0xA3, 0x7F, 0x63, 0x9E, 0x7F, 0x87, 0x67, 0xFC, 0x63, 0x54, 0x98, 0x00, 0x15, 0x3D, 0x4F, 0x99, 0xCD, 0x0F, 0x4A, 0xCC, 0x0D, 0x03, 0x16, 0x69, 0xB6, 0x67},
+ []uint{33, 50, 24, 24, 5, 53, 5, 61, 26, 56, 35, 50, 2, 22, 59, 54, 8, 7, 48, 13, 14, 27, 42, 37, 42, 3},
+ []uint64{0x19015E9D2, 0xCA8D3751639D, 0x92A674, 0x5BECA6, 0x1C, 0x16A704EDDA0743, 0x1A, 0x1104B1BDCF15BFC6, 0x13C9285, 0x142BBFEFF3BF95, 0x63B53D4FE, 0x19DF315DD647, 0x00, 0x144A34, 0x15CE9429CA93F3, 0x10A4841DF39EE1, 0x5C, 0x65, 0x41A2A8DFD8E7, 0x13FC, 0xECF, 0x7C63549, 0x200054F53E6, 0xE687A5660, 0x1A062CD36CC, 0x07},
+ },
+ {
+ []byte{0x83, 0x89, 0x65, 0xAD, 0xCF, 0xD1, 0xA9, 0x1F, 0xB5, 0x29, 0x97, 0x34, 0xA0, 0x5C, 0x67, 0xEC, 0x10, 0x7C, 0xB5, 0xB9, 0xB1, 0x3F, 0x70, 0xCD, 0x54, 0x37, 0xCF, 0x1A, 0x0A, 0xF8, 0x7C, 0x68, 0xF1, 0x7A, 0x4E, 0x69, 0x53, 0xAA, 0xBA, 0x8E, 0x42, 0xC8, 0x49, 0x28, 0xB4, 0xED, 0x55, 0x08, 0x88, 0x0D, 0xAF, 0xF1, 0x34, 0x2B, 0x4A, 0x14, 0x2F, 0x00, 0x2E, 0xB7, 0x9B, 0xEE, 0x86, 0x62, 0x25, 0x12, 0x39, 0xF6, 0x12, 0xD6, 0x9F, 0x95, 0x52, 0x68, 0x2F, 0x9B, 0x2E, 0xBC, 0x32, 0xC4, 0xC6, 0x98, 0x99, 0xB6, 0xB9, 0x93, 0x61, 0xA2, 0x07, 0x20, 0x70, 0x1D, 0x1C, 0x9F, 0xC3, 0xCF, 0x72, 0xFA, 0x4A, 0x1B},
+ []uint{47, 7, 1, 29, 41, 12, 14, 2, 46, 54, 62, 59, 12, 45, 62, 1, 6, 6, 50, 14, 23, 27, 45, 11, 51, 36, 20, 17},
+ []uint64{0x41C4B2D6E7E8, 0x6A, 0x00, 0x11FB5299, 0xE6940B8CFD, 0x820, 0x3E5A, 0x03, 0x1CD89FB866AA, 0x6F9E3415F0F8D, 0x78BD2734A9D55D4, 0x390B2124A2D3B55, 0x422, 0x406D7F89A15, 0x294285E005D6F37D, 0x01, 0x28, 0x19, 0x22251239F612D, 0x1A7E, 0x2AA4D0, 0x2F9B2EB, 0x1865898D3133, 0x36B, 0x4C9B0D1039038, 0xE8E4FE1E, 0x7B97D, 0x4A1B},
+ },
+ {
+ []byte{0x9D, 0xCF, 0xB2, 0x8C, 0xE0, 0xE6, 0xD3, 0xD4, 0xC0, 0x77, 0x4C, 0x43, 0xDB, 0xEE, 0x32, 0xD6, 0x67, 0x9F, 0xED, 0xAA, 0xB6, 0x0C, 0x1D, 0x65, 0x61, 0x02, 0xA1, 0xB0, 0x08, 0xB9, 0x06, 0xCF, 0xA1, 0xD4, 0xE0, 0x54, 0x75, 0x30, 0x59, 0xDA, 0xFE, 0x16, 0x9F, 0x36, 0x88, 0xD4, 0x70, 0x3D, 0xE4, 0x2E, 0x78, 0x17, 0x5F, 0x18, 0x5A, 0x7F, 0x35, 0x31, 0x63, 0xD0, 0xF9, 0xCF, 0x34, 0xD6, 0xDF, 0x7E, 0xB9, 0x07, 0x24, 0x37, 0x2B, 0x5C, 0xFC, 0xD0, 0x3B, 0x32, 0xD4, 0xA7, 0x96, 0x28, 0xD1, 0x23, 0xDA, 0x6C, 0xEA, 0x4C, 0x29, 0x31, 0xB2, 0x20, 0x3C, 0x23, 0xE2, 0xEB, 0x22, 0x78, 0x79, 0xD1, 0xBC, 0xEB},
+ []uint{49, 29, 9, 37, 23, 47, 33, 37, 49, 15, 60, 35, 21, 35, 36, 5, 9, 45, 31, 23, 18, 64, 13, 58, 19},
+ []uint64{0x13B9F6519C1CD, 0x14F5301D, 0x1A6, 0x43DBEE32D, 0x333CFF, 0x36AAD8307595, 0x108150D80, 0x8B906CFA1, 0x1A9C0A8EA60B3, 0x5AFE, 0x169F3688D4703DE, 0x2173C0BAF, 0x1185A7, 0x79A98B1E8, 0x7CE79A6B6, 0x1F, 0xFD, 0xE41C90DCAD7, 0x1F9A0766, 0x2D4A79, 0x18A34, 0x48F69B3A930A4C6C, 0x1101, 0x3847C5D644F0F3A, 0x1BCEB},
+ },
+ {
+ []byte{0x91, 0x0B, 0x7C, 0xD2, 0x4C, 0xB9, 0x12, 0xA4, 0x56, 0x7E, 0xE5, 0x29, 0xEC, 0x0D, 0xEE, 0xD9, 0xCD, 0x10, 0x96, 0x04, 0xDE, 0xAE, 0x9A, 0x8E, 0xFA, 0x41, 0x7C, 0x47, 0x22, 0x53, 0xD3, 0xBF, 0x1E, 0x78, 0x75, 0xBA, 0x7A, 0x88, 0x06, 0x39, 0xC3, 0x8C, 0x59, 0x79, 0x6B, 0x4F, 0x52, 0x30, 0x08, 0xF6, 0x7E, 0x0A, 0xB9, 0x74, 0xB8, 0x25, 0x9C, 0x20, 0x53, 0x7E, 0x4C, 0xAC, 0xE4, 0x58, 0x38, 0xCC, 0xAA, 0x55, 0xCA, 0xE9, 0x1F, 0x2A, 0xD8, 0x15, 0xB8, 0x53, 0x7D, 0xD3, 0x16, 0x47, 0x96, 0xC2, 0x98, 0x56, 0x35, 0xDB, 0x83, 0x5E, 0xD7, 0xCF, 0xB6, 0x03, 0x6A, 0xBF, 0x7A, 0x6C, 0x7A, 0x54, 0x99, 0x0C},
+ []uint{34, 58, 36, 43, 41, 55, 14, 6, 6, 12, 62, 43, 34, 27, 12, 29, 46, 25, 51, 13, 36, 42, 35, 40},
+ []uint64{0x2442DF349, 0xCB912A4567EE52, 0x9EC0DEED9, 0x66884B026F5, 0xE9A8EFA417, 0x6239129E9DF8F3, 0x30EB, 0x1D, 0x0F, 0x510, 0x31CE1C62CBCB5A7, 0x548C023D9F8, 0xAB974B82, 0x2CE1029, 0xBF2, 0xCACE458, 0xE332A9572BA, 0x8F956C, 0x56E14DF74C59, 0x3CB, 0x614C2B1AE, 0x3706BDAF9F6, 0x6036ABF7A, 0x6C7A54990C},
+ },
+ {
+ []byte{0xAE, 0x2E, 0x61, 0xAB, 0x47, 0x76, 0x8C, 0x9E, 0x28, 0x13, 0x95, 0x06, 0x9A, 0x10, 0x8A, 0x5B, 0xFD, 0xB2, 0x2F, 0xC5, 0x44, 0x29, 0xB3, 0xBF, 0x5B, 0x39, 0xD5, 0x5A, 0xD2, 0xED, 0x48, 0xA6, 0x09, 0x11, 0x37, 0x9A, 0x18, 0x04, 0xA2, 0xC5, 0x07, 0x94, 0xAF, 0x3F, 0x3C, 0x59, 0x3E, 0x8E, 0xE6, 0x9C, 0x25, 0x03, 0xFC, 0xFA, 0xB3, 0x95, 0xB8, 0xAD, 0x53, 0x12, 0x2F, 0xB9, 0x91, 0x9C, 0xD0, 0x93, 0x52, 0xF8, 0x03, 0x68, 0xD2, 0x72, 0xD4, 0x63, 0x2B, 0xAA, 0xFF, 0x92, 0x8E, 0xFB, 0x82, 0xC4, 0x41, 0xEC, 0x40, 0x0C, 0x9D, 0xFB, 0x40, 0x25, 0x0B, 0x2F, 0xB1, 0x34, 0x05, 0xD7, 0xB4, 0x73, 0xAE, 0x05},
+ []uint{20, 26, 55, 35, 26, 47, 15, 22, 5, 30, 16, 29, 32, 21, 47, 57, 49, 56, 32, 13, 23, 8, 54, 20, 31, 31},
+ []uint64{0xAE2E6, 0x6AD1DD, 0x5193C50272A0D3, 0x2108A5BFD, 0x2C8BF15, 0x853677EB673, 0x555A, 0x34BB52, 0x05, 0xC12226F, 0x3430, 0x128B141, 0xE52BCFCF, 0x2C9F4, 0x3B9A70940FF3, 0x1D59CADC56A9891, 0xFB9919CD0935, 0x2F80368D272D46, 0x32BAAFF9, 0x51D, 0x7B82C4, 0x41, 0x3B1003277ED009, 0x42CBE, 0x62680BAF, 0x3473AE05},
+ },
+ {
+ []byte{0xC3, 0x42, 0xF8, 0x38, 0x04, 0x5F, 0x4F, 0x7A, 0x7A, 0x2F, 0x32, 0xEC, 0xE5, 0x0F, 0xDD, 0x4C, 0x16, 0x10, 0x31, 0x0A, 0xF0, 0xAE, 0x6D, 0xE1, 0xEB, 0xE3, 0x4E, 0x11, 0x30, 0x6C, 0xC1, 0xA8, 0xA6, 0xB5, 0x33, 0xD3, 0x58, 0x03, 0xBF, 0x16, 0x09, 0x37, 0x4D, 0xE7, 0xE9, 0x82, 0xCC, 0xBC, 0xFA, 0x12, 0x4D, 0xAC, 0xF6, 0x53, 0x22, 0xBD, 0xF7, 0xFD, 0x22, 0x77, 0xEC, 0x5B, 0xD1, 0xC4, 0xA2, 0x97, 0xC9, 0x04, 0x1C, 0x62, 0x7B, 0xD4, 0x03, 0x82, 0x21, 0x22, 0x2B, 0x20, 0xC6, 0x0D, 0xF8, 0xAA, 0x03, 0xC0, 0x30, 0x21, 0x31, 0xF0, 0xEE, 0x9B, 0x17, 0x60, 0x24, 0x94, 0x71, 0x5F, 0x04, 0xC5, 0x21, 0x97},
+ []uint{62, 59, 50, 16, 6, 35, 61, 35, 43, 22, 8, 55, 5, 33, 27, 32, 33, 23, 21, 40, 38, 23, 2, 27, 43, 1},
+ []uint64{0x30D0BE0E0117D3DE, 0x4F45E65D9CA1FBA, 0x260B081885785, 0x736F, 0x03, 0x6BE34E113, 0xD983514D6A67A6, 0x5803BF160, 0x49BA6F3F4C1, 0x19979F, 0x42, 0x24DACF65322BDF, 0x0F, 0x1F489DFB1, 0x37A3894, 0x52F92083, 0x1189EF500, 0x704424, 0x8AC83, 0x1837E2A80F, 0x302131F0, 0x774D8B, 0x02, 0x6024947, 0xAF826290CB, 0x01},
+ },
+ {
+ []byte{0xDB, 0xB6, 0x8B, 0x84, 0x54, 0x5F, 0x96, 0xF5, 0xA7, 0x0A, 0x0C, 0x86, 0x2B, 0x97, 0x6C, 0x1D, 0x06, 0xF1, 0x2B, 0x6B, 0x3C, 0xD6, 0xE2, 0x4E, 0x00, 0x50, 0xFF, 0x99, 0x4E, 0x19, 0x48, 0xC0, 0x51, 0xAE, 0x3F, 0x8A, 0x89, 0xB5, 0x4E, 0x1D, 0x4B, 0xA7, 0x4E, 0xC6, 0xF9, 0x51, 0x4C, 0xAC, 0xFA, 0x68, 0x40, 0xB1, 0xD6, 0xA5, 0x40, 0xF3, 0xCD, 0xDC, 0xCB, 0x3B, 0x5E, 0xBD, 0x4D, 0x42, 0xA1, 0xDE, 0x60, 0x5F, 0xFF, 0x04, 0xB8, 0xC4, 0xC6, 0xCC, 0x6D, 0xAE, 0xE0, 0xD4, 0x5C, 0x19, 0x12, 0x0C, 0xE1, 0x5D, 0xEA, 0x52, 0x81, 0x48, 0x36, 0x7E, 0xB4, 0x3E, 0x2F, 0x55, 0xE8, 0xF1, 0x5C, 0xCC, 0xE9, 0x69},
+ []uint{40, 14, 56, 38, 64, 31, 42, 45, 46, 13, 7, 51, 4, 7, 54, 61, 37, 57, 15, 30, 56, 32},
+ []uint64{0xDBB68B8454, 0x17E5, 0xBD69C283218AE5, 0x36C1D06F12, 0xB6B3CD6E24E0050F, 0x7CCA70CA, 0x1180A35C7F1, 0xA26D538752E, 0x274EC6F9514C, 0x159F, 0x26, 0x42058EB52A079, 0x0E, 0x37, 0x1CCB3B5EBD4D42, 0x143BCC0BFFE09718, 0x131B31B6BB, 0x106A2E0C890670A, 0x77A9, 0x12814836, 0x7EB43E2F55E8F1, 0x5CCCE969},
+ },
+ {
+ []byte{0xC1, 0xD6, 0x8F, 0x43, 0xE4, 0xDA, 0x73, 0x69, 0xFF, 0xD2, 0xBD, 0x90, 0x9C, 0xA7, 0x7F, 0x80, 0x19, 0x74, 0xED, 0xAA, 0xFC, 0x25, 0x6C, 0xB8, 0x2B, 0xD9, 0xE1, 0x2F, 0xC1, 0xD8, 0xCF, 0x8C, 0x5F, 0xA9, 0xA7, 0x4A, 0x4B, 0xFD, 0x69, 0x5D, 0x81, 0x47, 0x74, 0x01, 0x04, 0xC0, 0xE2, 0x44, 0xC0, 0x6A, 0x9D, 0x55, 0x36, 0x67, 0x97, 0x1D, 0xA5, 0x77, 0xF1, 0x66, 0xA7, 0xFF, 0x9A, 0xE7, 0xE7, 0x2C, 0x11, 0xBA, 0xD1, 0x35, 0xAB, 0xFE, 0x6E, 0x1B, 0x4E, 0x71, 0x8E, 0xE1, 0x76, 0x9A, 0x37, 0xC9, 0xB9, 0x0D, 0xE7, 0x48, 0xE3, 0xF5, 0x1B, 0xD0, 0x37, 0xAD, 0xB5, 0x6A, 0x5D, 0x1D, 0x68, 0xA6, 0x25, 0xA5},
+ []uint{43, 24, 64, 30, 32, 57, 56, 61, 50, 3, 45, 46, 3, 60, 22, 42, 5, 60, 20, 24, 10, 43},
+ []uint64{0x60EB47A1F26, 0xD39B4F, 0xFE95EC84E53BFC00, 0x32E9DB55, 0xF84AD970, 0xAF6784BF07633E, 0x317EA69D292FF5, 0x14AEC0A3BA008260, 0x1C48980D53AAA, 0x03, 0xCCF2E3B4AEF, 0x38B353FFCD73, 0x07, 0x9CB046EB44D6AFF, 0x26E1B4, 0x39C63B85DA6, 0x11, 0xBE4DC86F3A471FA, 0x8DE81, 0xBD6DAB, 0x14B, 0x51D68A625A5},
+ },
+ {
+ []byte{0xD2, 0x0F, 0x71, 0xCA, 0xCA, 0xC7, 0x54, 0x23, 0xD0, 0x56, 0x71, 0xA4, 0x96, 0x84, 0x3D, 0xA6, 0x34, 0x6E, 0x5E, 0x7F, 0x4E, 0x49, 0x22, 0xE0, 0x9E, 0xC8, 0x94, 0x2E, 0xAF, 0x34, 0x2F, 0xF6, 0xD3, 0xA7, 0x90, 0x9E, 0xEC, 0x25, 0x15, 0xC5, 0xFB, 0xE4, 0xBD, 0x08, 0x3D, 0x5A, 0x70, 0x77, 0x17, 0x20, 0x2F, 0x1B, 0x1B, 0xAB, 0xA5, 0xC9, 0x83, 0x6D, 0x44, 0x21, 0xD6, 0x0A, 0x01, 0xBD, 0x5D, 0x9F, 0xFD, 0xE4, 0xDF, 0xE4, 0xFD, 0x83, 0xA2, 0x7C, 0xAF, 0x23, 0x7B, 0xB1, 0x6B, 0xAA, 0x71, 0x50, 0x11, 0xBB, 0x48, 0x66, 0xE8, 0x6C, 0xF4, 0x42, 0x28, 0x36, 0x78, 0xEE, 0x64, 0xA5, 0xEA, 0xFC, 0x2E, 0x5A},
+ []uint{32, 19, 41, 28, 7, 20, 33, 64, 3, 54, 63, 16, 12, 12, 63, 9, 64, 3, 29, 29, 18, 6, 28, 3, 2, 39, 41, 40, 22},
+ []uint64{0xD20F71CA, 0x6563A, 0x1423D05671A, 0x496843D, 0x53, 0x1A372, 0x1E7F4E492, 0x2E09EC8942EAF342, 0x07, 0x3EDA74F213DD84, 0x515C5FBE4BD083D5, 0xA707, 0x717, 0x202, 0x78D8DD5D2E4C1B6A, 0x42, 0x1D60A01BD5D9FFDE, 0x02, 0xDFE4FD8, 0x744F95E, 0x11BDD, 0x22, 0xD754E2A, 0x00, 0x00, 0x237690CDD0, 0x1B3D108A0D9, 0xE3B99297AB, 0x3C2E5A},
+ },
+ {
+ []byte{0x97, 0xD2, 0x7B, 0x0E, 0xF3, 0x1D, 0x05, 0xA6, 0x82, 0x27, 0xD8, 0xE0, 0x4C, 0x2C, 0xFE, 0x8E, 0x5B, 0x92, 0x67, 0xA1, 0xDA, 0x2F, 0xC8, 0x6A, 0x3F, 0x83, 0x20, 0x33, 0xB2, 0xF7, 0xE6, 0x6E, 0xE2, 0x93, 0x98, 0xA2, 0x32, 0x15, 0xD1, 0x21, 0x41, 0xBC, 0x2B, 0xDE, 0xFE, 0x55, 0xFB, 0x6C, 0x34, 0x28, 0xC4, 0x41, 0xA1, 0xFE, 0x33, 0x0C, 0xD3, 0xF5, 0x4A, 0x90, 0xF7, 0x58, 0x04, 0x0C, 0xB6, 0xEE, 0x44, 0xCC, 0x80, 0x3F, 0x00, 0x8F, 0xA8, 0x85, 0xE8, 0x9C, 0x9D, 0xF5, 0x5A, 0xEA, 0xA0, 0x6B, 0x3B, 0x59, 0xD1, 0x89, 0x81, 0x5A, 0xE0, 0x10, 0xD5, 0xD3, 0x7B, 0x1A, 0x4E, 0xAF, 0x3D, 0xE9, 0x3E, 0x59},
+ []uint{22, 40, 15, 18, 48, 34, 7, 54, 40, 57, 21, 10, 60, 13, 5, 38, 25, 14, 28, 20, 11, 53, 9, 36, 23, 46, 17, 4, 32},
+ []uint64{0x25F49E, 0xC3BCC74169, 0x5044, 0x3EC70, 0x26167F472DC9, 0xCF43B45F, 0x48, 0x1A8FE0C80CECBD, 0xF99BB8A4E6, 0x51190AE890A0DE, 0x2BDEF, 0x395, 0x7EDB0D0A3110687, 0x1F19, 0x10, 0x334FD52A43, 0x1BAC020, 0x196D, 0xDC89990, 0x7E01, 0xFA, 0x110BD1393BEAB5, 0x1AA, 0x81ACED674, 0x31302B, 0x170086AE9BD8, 0x1A4EA, 0x0F, 0x3DE93E59},
+ },
+ {
+ []byte{0xAB, 0x5F, 0xA3, 0x18, 0x91, 0x10, 0x4D, 0x85, 0x95, 0xC6, 0x23, 0xBA, 0x0D, 0xBD, 0xC4, 0x2A, 0x12, 0x30, 0xE1, 0xD3, 0xFE, 0xA2, 0x0B, 0xB9, 0xD9, 0x3D, 0x61, 0x91, 0x97, 0x8B, 0x53, 0x2A, 0xC1, 0x80, 0x3C, 0x46, 0x46, 0x44, 0x57, 0x8A, 0x23, 0x66, 0xF2, 0x51, 0xCC, 0xF8, 0xFB, 0xEF, 0x0A, 0x0B, 0x72, 0xF0, 0xA8, 0x36, 0xE7, 0x26, 0x04, 0x83, 0x15, 0x36, 0x04, 0x73, 0x38, 0x48, 0x41, 0x61, 0x0B, 0x09, 0x46, 0xBC, 0x29, 0xA8, 0x02, 0xB6, 0x80, 0xDB, 0xCF, 0x22, 0x54, 0x5B, 0x5A, 0x2E, 0x34, 0x24, 0x06, 0xB9, 0x66, 0x4C, 0xD1, 0xB7, 0x1A, 0xFF, 0x92, 0x06, 0x49, 0xD1, 0x26, 0xE6, 0x23, 0xAD},
+ []uint{61, 43, 8, 31, 38, 4, 45, 5, 51, 58, 5, 2, 51, 22, 38, 44, 26, 20, 52, 51, 49, 39, 50, 7},
+ []uint64{0x156BF463122209B0, 0x595C623BA0D, 0xBD, 0x62150918, 0x1C3A7FD441, 0x07, 0xE764F586465, 0x1C, 0x2D4CAB0600F11, 0x24644578A2366F2, 0x0A, 0x00, 0x733E3EFBC282D, 0x32F0A8, 0xDB9C98120, 0xC54D811CCE1, 0x841610, 0xB0946, 0xBC29A802B680D, 0x5E7912A2DAD17, 0x342406B9664C, 0x68DB8D7FC9, 0xC93A24DCC47, 0x2D},
+ },
+ {
+ []byte{0xAA, 0x55},
+ []uint{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ []uint64{1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1},
+ },
+
+ {
+ []byte{0xAA, 0x55},
+ []uint{7, 8, 1},
+ []uint64{0x55, 0x2A, 0x1},
+ },
+
+ {
+ []byte{0xAA, 0x55},
+ []uint{3, 3, 3, 3, 3, 1},
+ []uint64{0x5, 0x2, 0x4, 0x5, 0x2, 0x1},
+ },
+
+ {
+ []byte{0xAA, 0x55},
+ []uint{16},
+ []uint64{0xAA55},
+ },
+
+ {
+ []byte{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55},
+ []uint{32, 32},
+ []uint64{0xAA55AA55, 0xAA55AA55},
+ },
+
+ {
+ []byte{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55},
+ []uint{33, 31},
+ []uint64{0x154AB54AB, 0x2A55AA55},
+ },
+ }
+
+ for i, test := range tests {
+ r := NewReader(bytes.NewReader(test.data))
+ if len(test.ns) != len(test.vals) {
+ panic("Number of reads does not match number of results")
+ }
+ for j, n := range test.ns {
+ m, err := r.Read(n)
+ if err != nil {
+ panic("Unexpected error: " + err.Error())
+ }
+ if m != test.vals[j] {
+ t.Errorf("i=%d; %v with reads %v: read %d gave %x, expected %x", i, test.data, test.ns, j, m, test.vals[j])
+ }
+ }
+ }
+}
+
+func TestReadEOF(t *testing.T) {
+ tests := []struct {
+ data []byte
+ n uint
+ err error
+ }{
+ {[]byte{0xFF}, 8, nil},
+ {[]byte{0xFF}, 2, nil},
+ {[]byte{0xFF}, 9, io.ErrUnexpectedEOF},
+ {[]byte{}, 1, io.EOF},
+ {[]byte{0xFF, 0xFF}, 16, nil},
+ {[]byte{0xFF, 0xFF}, 17, io.ErrUnexpectedEOF},
+ }
+
+ for i, test := range tests {
+ r := NewReader(bytes.NewReader(test.data))
+ if _, err := r.Read(test.n); err != test.err {
+ t.Errorf("i=%d; Reading %d from %v, expected err=%s, got err=%s", i, test.n, test.data, test.err, err)
+ }
+ }
+}
+
+func BenchmarkReadAlign1(b *testing.B) {
+ benchmarkReads(b, 64, 1)
+}
+
+func BenchmarkReadAlign32(b *testing.B) {
+ benchmarkReads(b, 64, 32)
+}
+
+func BenchmarkReadAlign64(b *testing.B) {
+ benchmarkReads(b, 64, 64)
+}
+
+func benchmarkReads(b *testing.B, chunk, align int) {
+ size := 1 << 12
+ buf, bits, _, last := prepareBenchmark(size, chunk, align)
+ b.SetBytes(int64(len(buf)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ r := NewReader(bytes.NewReader(buf))
+ for j := 0; j < last; j++ {
+ if _, err := r.Read(bits[j]); err != nil {
+ b.Error(err)
+ continue
+ }
+ }
+ }
+}
+
+func prepareBenchmark(size, chunk, align int) ([]byte, []uint, []uint64, int) {
+ buf := make([]byte, size)
+ bits := make([]uint, size)
+ values := make([]uint64, size)
+ idx := 0
+ last := 0
+ for i := 0; i < size; i++ {
+ val := getNumBits(idx, size*8, chunk, align)
+ idx += val
+ if val != 0 {
+ last = i + 1
+ }
+ bits[i] = uint(val)
+ values[i] = uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
+ }
+ return buf, bits, values, last
+}
+
+func getNumBits(read, max, chunk, align int) int {
+ bits := 1
+ if align != chunk {
+ bits += rand.Intn(chunk / align)
+ }
+ bits *= align
+ if read+bits > max {
+ bits = max - read
+ }
+ if bits > chunk {
+ panic("too many bits")
+ }
+ return bits
+}
diff --git a/internal/bits/twocomp.go b/internal/bits/twocomp.go
new file mode 100755
index 0000000..45d52b4
--- /dev/null
+++ b/internal/bits/twocomp.go
@@ -0,0 +1,27 @@
+package bits
+
+// IntN returns the signed two's complement of x with the specified integer bit
+// width.
+//
+// Examples of unsigned (n-bit width) x values on the left and decoded values on
+// the right:
+//
+// 0b011 -> 3
+// 0b010 -> 2
+// 0b001 -> 1
+// 0b000 -> 0
+// 0b111 -> -1
+// 0b110 -> -2
+// 0b101 -> -3
+// 0b100 -> -4
+func IntN(x uint64, n uint) int64 {
+ signBitMask := uint64(1 << (n - 1))
+ if x&signBitMask == 0 {
+ // positive.
+ return int64(x)
+ }
+ // negative.
+ v := int64(x ^ signBitMask) // clear sign bit.
+ v -= int64(signBitMask)
+ return v
+}
diff --git a/internal/bits/twocomp_test.go b/internal/bits/twocomp_test.go
new file mode 100755
index 0000000..d803889
--- /dev/null
+++ b/internal/bits/twocomp_test.go
@@ -0,0 +1,27 @@
+package bits
+
+import "testing"
+
+func TestIntN(t *testing.T) {
+ golden := []struct {
+ x uint64
+ n uint
+ want int64
+ }{
+ {x: 0b011, n: 3, want: 3},
+ {x: 0b010, n: 3, want: 2},
+ {x: 0b001, n: 3, want: 1},
+ {x: 0b000, n: 3, want: 0},
+ {x: 0b111, n: 3, want: -1},
+ {x: 0b110, n: 3, want: -2},
+ {x: 0b101, n: 3, want: -3},
+ {x: 0b100, n: 3, want: -4},
+ }
+ for _, g := range golden {
+ got := IntN(g.x, g.n)
+ if g.want != got {
+ t.Errorf("result mismatch of IntN(x=0b%03b, n=%d); expected %d, got %d", g.x, g.n, g.want, got)
+ continue
+ }
+ }
+}
diff --git a/internal/bits/unary.go b/internal/bits/unary.go
new file mode 100755
index 0000000..b4a81fc
--- /dev/null
+++ b/internal/bits/unary.go
@@ -0,0 +1,58 @@
+package bits
+
+import (
+ "github.com/icza/bitio"
+)
+
+// ReadUnary decodes and returns an unary coded integer, whose value is
+// represented by the number of leading zeros before a one.
+//
+// Examples of unary coded binary on the left and decoded decimal on the right:
+//
+// 1 => 0
+// 01 => 1
+// 001 => 2
+// 0001 => 3
+// 00001 => 4
+// 000001 => 5
+// 0000001 => 6
+func (br *Reader) ReadUnary() (x uint64, err error) {
+ for {
+ bit, err := br.Read(1)
+ if err != nil {
+ return 0, err
+ }
+ if bit == 1 {
+ break
+ }
+ x++
+ }
+ return x, nil
+}
+
+// WriteUnary encodes x as an unary coded integer, whose value is represented by
+// the number of leading zeros before a one.
+//
+// Examples of unary coded binary on the left and decoded decimal on the right:
+//
+// 0 => 1
+// 1 => 01
+// 2 => 001
+// 3 => 0001
+// 4 => 00001
+// 5 => 000001
+// 6 => 0000001
+func WriteUnary(bw *bitio.Writer, x uint64) error {
+ for ; x > 8; x -= 8 {
+ if err := bw.WriteByte(0x0); err != nil {
+ return err
+ }
+ }
+
+ bits := uint64(1)
+ n := byte(x + 1)
+ if err := bw.WriteBits(bits, n); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/internal/bits/unary_test.go b/internal/bits/unary_test.go
new file mode 100755
index 0000000..4db524a
--- /dev/null
+++ b/internal/bits/unary_test.go
@@ -0,0 +1,36 @@
+package bits_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/icza/bitio"
+ "github.com/mewkiz/flac/internal/bits"
+)
+
+func TestUnary(t *testing.T) {
+ buf := &bytes.Buffer{}
+ bw := bitio.NewWriter(buf)
+
+ for want := uint64(0); want < 1000; want++ {
+ // Write unary
+ if err := bits.WriteUnary(bw, want); err != nil {
+ t.Fatalf("unable to write unary; %v", err)
+ }
+ // Flush buffer
+ if err := bw.Close(); err != nil {
+ t.Fatalf("unable to close (flush) the bit buffer; %v", err)
+ }
+
+ // Read written unary
+ r := bits.NewReader(buf)
+ got, err := r.ReadUnary()
+ if err != nil {
+ t.Fatalf("unable to read unary; %v", err)
+ }
+
+ if want != got {
+ t.Fatalf("mismatch between written and read unary value; expected: %d, got: %d", want, got)
+ }
+ }
+}
diff --git a/internal/bits/zigzag.go b/internal/bits/zigzag.go
new file mode 100755
index 0000000..3d6ac40
--- /dev/null
+++ b/internal/bits/zigzag.go
@@ -0,0 +1,41 @@
+package bits
+
+// DecodeZigZag decodes a ZigZag encoded integer and returns it.
+//
+// Examples of ZigZag encoded values on the left and decoded values on the
+// right:
+//
+// 0 => 0
+// 1 => -1
+// 2 => 1
+// 3 => -2
+// 4 => 2
+// 5 => -3
+// 6 => 3
+//
+// ref: https://developers.google.com/protocol-buffers/docs/encoding
+func DecodeZigZag(x uint32) int32 {
+ return int32(x>>1) ^ -int32(x&1)
+}
+
+// EncodeZigZag encodes a given integer to ZigZag-encoding.
+//
+// Examples of integer input on the left and corresponding ZigZag encoded values
+// on the right:
+//
+// 0 => 0
+// -1 => 1
+// 1 => 2
+// -2 => 3
+// 2 => 4
+// -3 => 5
+// 3 => 6
+//
+// ref: https://developers.google.com/protocol-buffers/docs/encoding
+func EncodeZigZag(x int32) uint32 {
+ if x < 0 {
+ x = -x
+ return uint32(x)<<1 - 1
+ }
+ return uint32(x) << 1
+}
diff --git a/internal/bits/zigzag_test.go b/internal/bits/zigzag_test.go
new file mode 100755
index 0000000..2a8fdc5
--- /dev/null
+++ b/internal/bits/zigzag_test.go
@@ -0,0 +1,49 @@
+package bits
+
+import (
+ "testing"
+)
+
+func TestDecodeZigZag(t *testing.T) {
+ golden := []struct {
+ x uint32
+ want int32
+ }{
+ {x: 0, want: 0},
+ {x: 1, want: -1},
+ {x: 2, want: 1},
+ {x: 3, want: -2},
+ {x: 4, want: 2},
+ {x: 5, want: -3},
+ {x: 6, want: 3},
+ }
+ for _, g := range golden {
+ got := DecodeZigZag(g.x)
+ if g.want != got {
+ t.Errorf("result mismatch of DecodeZigZag(x=%d); expected %d, got %d", g.x, g.want, got)
+ continue
+ }
+ }
+}
+
+func TestEncodeZigZag(t *testing.T) {
+ golden := []struct {
+ x int32
+ want uint32
+ }{
+ {x: 0, want: 0},
+ {x: -1, want: 1},
+ {x: 1, want: 2},
+ {x: -2, want: 3},
+ {x: 2, want: 4},
+ {x: -3, want: 5},
+ {x: 3, want: 6},
+ }
+ for _, g := range golden {
+ got := EncodeZigZag(g.x)
+ if g.want != got {
+ t.Errorf("result mismatch of EncodeZigZag(x=%d); expected %d, got %d", g.x, g.want, got)
+ continue
+ }
+ }
+}
diff --git a/internal/bufseekio/readseeker.go b/internal/bufseekio/readseeker.go
new file mode 100755
index 0000000..9678eda
--- /dev/null
+++ b/internal/bufseekio/readseeker.go
@@ -0,0 +1,152 @@
+package bufseekio
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ defaultBufSize = 4096
+)
+
+// ReadSeeker implements buffering for an io.ReadSeeker object.
+// ReadSeeker is based on bufio.Reader with Seek functionality added
+// and unneeded functionality removed.
+type ReadSeeker struct {
+ buf []byte
+ pos int64 // absolute start position of buf
+ rd io.ReadSeeker // read-seeker provided by the client
+ r, w int // buf read and write positions within buf
+ err error
+}
+
+const minReadBufferSize = 16
+
+// NewReadSeekerSize returns a new ReadSeeker whose buffer has at least the specified
+// size. If the argument io.ReadSeeker is already a ReadSeeker with large enough
+// size, it returns the underlying ReadSeeker.
+func NewReadSeekerSize(rd io.ReadSeeker, size int) *ReadSeeker {
+ // Is it already a Reader?
+ b, ok := rd.(*ReadSeeker)
+ if ok && len(b.buf) >= size {
+ return b
+ }
+ if size < minReadBufferSize {
+ size = minReadBufferSize
+ }
+ r := new(ReadSeeker)
+ r.reset(make([]byte, size), rd)
+ return r
+}
+
+// NewReadSeeker returns a new ReadSeeker whose buffer has the default size.
+func NewReadSeeker(rd io.ReadSeeker) *ReadSeeker {
+ return NewReadSeekerSize(rd, defaultBufSize)
+}
+
+var errNegativeRead = errors.New("bufseekio: reader returned negative count from Read")
+
+func (b *ReadSeeker) reset(buf []byte, r io.ReadSeeker) {
+ *b = ReadSeeker{
+ buf: buf,
+ rd: r,
+ }
+}
+
+func (b *ReadSeeker) readErr() error {
+ err := b.err
+ b.err = nil
+ return err
+}
+
+// Read reads data into p.
+// It returns the number of bytes read into p.
+// The bytes are taken from at most one Read on the underlying Reader,
+// hence n may be less than len(p).
+// To read exactly len(p) bytes, use io.ReadFull(b, p).
+// If the underlying Reader can return a non-zero count with io.EOF,
+// then this Read method can do so as well; see the [io.Reader] docs.
+func (b *ReadSeeker) Read(p []byte) (n int, err error) {
+ n = len(p)
+ if n == 0 {
+ if b.buffered() > 0 {
+ return 0, nil
+ }
+ return 0, b.readErr()
+ }
+ if b.r == b.w {
+ if b.err != nil {
+ return 0, b.readErr()
+ }
+ if len(p) >= len(b.buf) {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ n, b.err = b.rd.Read(p)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ b.pos += int64(n)
+ return n, b.readErr()
+ }
+ // One read.
+ b.pos += int64(b.r)
+ b.r = 0
+ b.w = 0
+ n, b.err = b.rd.Read(b.buf)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ if n == 0 {
+ return 0, b.readErr()
+ }
+ b.w += n
+ }
+
+ // copy as much as we can
+ // Note: if the slice panics here, it is probably because
+ // the underlying reader returned a bad count. See issue 49795.
+ n = copy(p, b.buf[b.r:b.w])
+ b.r += n
+ return n, nil
+}
+
+// buffered returns the number of bytes that can be read from the current buffer.
+func (b *ReadSeeker) buffered() int { return b.w - b.r }
+
+func (b *ReadSeeker) Seek(offset int64, whence int) (int64, error) {
+ // The stream.Seek() implementation makes heavy use of seeking with offset 0
+ // to obtain the current position; let's optimize for it.
+ if offset == 0 && whence == io.SeekCurrent {
+ return b.position(), nil
+ }
+ // When seeking from the end, the absolute position isn't known by ReadSeeker
+ // so the current buffer cannot be used. Seeking cannot be avoided.
+ if whence == io.SeekEnd {
+ return b.seek(offset, whence)
+ }
+ // Calculate the absolute offset.
+ abs := offset
+ if whence == io.SeekCurrent {
+ abs += b.position()
+ }
+ // Check if the offset is within buf.
+ if abs >= b.pos && abs < b.pos+int64(b.w) {
+ b.r = int(abs - b.pos)
+ return abs, nil
+ }
+
+ return b.seek(abs, io.SeekStart)
+}
+
+func (b *ReadSeeker) seek(offset int64, whence int) (int64, error) {
+ b.r = 0
+ b.w = 0
+ var err error
+ b.pos, err = b.rd.Seek(offset, whence)
+ return b.pos, err
+}
+
+// position returns the absolute read offset.
+func (b *ReadSeeker) position() int64 {
+ return b.pos + int64(b.r)
+}
diff --git a/internal/bufseekio/readseeker_test.go b/internal/bufseekio/readseeker_test.go
new file mode 100755
index 0000000..06b162d
--- /dev/null
+++ b/internal/bufseekio/readseeker_test.go
@@ -0,0 +1,266 @@
+package bufseekio
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "reflect"
+ "testing"
+)
+
+func TestNewReadSeekerSize(t *testing.T) {
+ buf := bytes.NewReader(make([]byte, 100))
+
+ // Test custom buffer size.
+ if rs := NewReadSeekerSize(buf, 20); len(rs.buf) != 20 {
+ t.Fatalf("want %d got %d", 20, len(rs.buf))
+ }
+
+ // Test too small buffer size.
+ if rs := NewReadSeekerSize(buf, 1); len(rs.buf) != minReadBufferSize {
+ t.Fatalf("want %d got %d", minReadBufferSize, len(rs.buf))
+ }
+
+ // Test reuse existing ReadSeeker.
+ rs := NewReadSeekerSize(buf, 20)
+ if rs2 := NewReadSeekerSize(rs, 5); rs != rs2 {
+ t.Fatal("expected ReadSeeker to be reused but got a different ReadSeeker")
+ }
+}
+
+func TestNewReadSeeker(t *testing.T) {
+ buf := bytes.NewReader(make([]byte, 100))
+ if rs := NewReadSeeker(buf); len(rs.buf) != defaultBufSize {
+ t.Fatalf("want %d got %d", defaultBufSize, len(rs.buf))
+ }
+}
+
+func TestReadSeeker_Read(t *testing.T) {
+ data := make([]byte, 100)
+ for i := range data {
+ data[i] = byte(i)
+ }
+ rs := NewReadSeekerSize(bytes.NewReader(data), 20)
+ if len(rs.buf) != 20 {
+ t.Fatal("the buffer size was changed and the validity of this test has become unknown")
+ }
+
+ // Test small read.
+ got := make([]byte, 5)
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{0, 1, 2, 3, 4}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{0, 1, 2, 3, 4}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 5 {
+ t.Fatalf("want %d got %d, err=%v", 5, p, err)
+ }
+
+ // Test big read with initially filled buffer.
+ got = make([]byte, 25)
+ if n, err := rs.Read(got); err != nil || n != 15 || !reflect.DeepEqual(got, []byte{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 15, n, []byte{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 20 {
+ t.Fatalf("want %d got %d, err=%v", 20, p, err)
+ }
+
+ // Test big read with initially empty buffer.
+ if n, err := rs.Read(got); err != nil || n != 25 || !reflect.DeepEqual(got, []byte{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 25, n, []byte{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 45 {
+ t.Fatalf("want %d got %d, err=%v", 45, p, err)
+ }
+
+ // Test EOF.
+ if p, err := rs.Seek(98, io.SeekStart); err != nil || p != 98 {
+ t.Fatalf("want %d got %d, err=%v", 98, p, err)
+ }
+ got = make([]byte, 5)
+ if n, err := rs.Read(got); err != nil || n != 2 || !reflect.DeepEqual(got, []byte{98, 99, 0, 0, 0}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 2, n, []byte{98, 99, 0, 0, 0}, got, err)
+ }
+ if n, err := rs.Read(got); err != io.EOF || n != 0 {
+ t.Fatalf("want n read %d got %d, err=%v", 0, n, err)
+ }
+
+ // Test source that returns bytes and an error at the same time.
+ rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20)
+ if len(rs.buf) != 20 {
+ t.Fatal("the buffer size was changed and the validity of this test has become unknown")
+ }
+ got = make([]byte, 5)
+ if n, err := rs.Read(got); err != nil || n != 3 || !reflect.DeepEqual(got, []byte{2, 3, 5, 0, 0}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 3, n, []byte{2, 3, 5, 0, 0}, got, err)
+ }
+ if n, err := rs.Read(got); err != expectedErr || n != 0 {
+ t.Fatalf("want n read %d got %d, want error %v, got %v", 0, n, expectedErr, err)
+ }
+
+ // Test read nothing with an empty buffer and a queued error.
+ rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20)
+ if len(rs.buf) != 20 {
+ t.Fatal("the buffer size was changed and the validity of this test has become unknown")
+ }
+ got = make([]byte, 3)
+ if n, err := rs.Read(got); err != nil || n != 3 || !reflect.DeepEqual(got, []byte{2, 3, 5}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 3, n, []byte{2, 3, 5}, got, err)
+ }
+ if n, err := rs.Read(nil); err != expectedErr || n != 0 {
+ t.Fatalf("want n read %d got %d, want error %v, got %v", 0, n, expectedErr, err)
+ }
+ if n, err := rs.Read(nil); err != nil || n != 0 {
+ t.Fatalf("want n read %d got %d, err=%v", 0, n, err)
+ }
+
+ // Test read nothing with a non-empty buffer and a queued error.
+ rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20)
+ if len(rs.buf) != 20 {
+ t.Fatal("the buffer size was changed and the validity of this test has become unknown")
+ }
+ got = make([]byte, 1)
+ if n, err := rs.Read(got); err != nil || n != 1 || !reflect.DeepEqual(got, []byte{2}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 1, n, []byte{}, got, err)
+ }
+ if n, err := rs.Read(nil); err != nil || n != 0 {
+ t.Fatalf("want n read %d got %d, err=%v", 0, n, err)
+ }
+}
+
+var expectedErr = errors.New("expected error")
+
+type readAndError struct {
+ bytes []byte
+}
+
+func (r *readAndError) Read(p []byte) (n int, err error) {
+ for i, b := range r.bytes {
+ p[i] = b
+ }
+ return len(r.bytes), expectedErr
+}
+
+func (r *readAndError) Seek(offset int64, whence int) (int64, error) {
+ panic("not implemented")
+}
+
+func TestReadSeeker_Seek(t *testing.T) {
+ data := make([]byte, 100)
+ for i := range data {
+ data[i] = byte(i)
+ }
+ r := &seekRecorder{rs: bytes.NewReader(data)}
+ rs := NewReadSeekerSize(r, 20)
+ if len(rs.buf) != 20 {
+ t.Fatal("the buffer size was changed and the validity of this test has become unknown")
+ }
+
+ got := make([]byte, 5)
+
+ // Test with io.SeekStart
+ if p, err := rs.Seek(10, io.SeekStart); err != nil || p != 10 {
+ t.Fatalf("want %d got %d, err=%v", 10, p, err)
+ }
+ r.assertSeeked(t, []seekRecord{{10, io.SeekStart}})
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{10, 11, 12, 13, 14}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{10, 11, 12, 13, 14}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 15 {
+ t.Fatalf("want %d got %d, err=%v", 15, p, err)
+ }
+ r.assertSeeked(t, nil)
+
+ // Test with io.SeekCurrent and positive offset within buffer.
+ if p, err := rs.Seek(5, io.SeekCurrent); err != nil || p != 20 {
+ t.Fatalf("want %d got %d, err=%v", 20, p, err)
+ }
+ r.assertSeeked(t, nil)
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{20, 21, 22, 23, 24}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{20, 21, 22, 23, 24}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 25 {
+ t.Fatalf("want %d got %d, err=%v", 25, p, err)
+ }
+
+ // Test with io.SeekCurrent and negative offset within buffer.
+ if p, err := rs.Seek(-10, io.SeekCurrent); err != nil || p != 15 {
+ t.Fatalf("want %d got %d, err=%v", 15, p, err)
+ }
+ r.assertSeeked(t, nil)
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{15, 16, 17, 18, 19}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{15, 16, 17, 18, 19}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 20 {
+ t.Fatalf("want %d got %d, err=%v", 20, p, err)
+ }
+
+ // Test with io.SeekCurrent and positive offset outside buffer.
+ if p, err := rs.Seek(30, io.SeekCurrent); err != nil || p != 50 {
+ t.Fatalf("want %d got %d, err=%v", 50, p, err)
+ }
+ r.assertSeeked(t, []seekRecord{{50, io.SeekStart}})
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{50, 51, 52, 53, 54}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{50, 51, 52, 53, 54}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 55 {
+ t.Fatalf("want %d got %d, err=%v", 55, p, err)
+ }
+
+ // Test seek with io.SeekEnd within buffer.
+ if p, err := rs.Seek(-45, io.SeekEnd); err != nil || p != 55 {
+ t.Fatalf("want %d got %d, err=%v", 55, p, err)
+ }
+ r.assertSeeked(t, []seekRecord{{-45, io.SeekEnd}})
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{55, 56, 57, 58, 59}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{55, 56, 57, 58, 59}, got, err)
+ }
+ if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 60 {
+ t.Fatalf("want %d got %d, err=%v", 60, p, err)
+ }
+
+ // Test seek with error.
+ if _, err := rs.Seek(-100, io.SeekStart); err == nil || err.Error() != "bytes.Reader.Seek: negative position" {
+ t.Fatalf("want error 'bytes.Reader.Seek: negative position' got %v", err)
+ }
+ r.assertSeeked(t, []seekRecord{{-100, io.SeekStart}})
+
+ // Test seek after error.
+ if p, err := rs.Seek(10, io.SeekStart); err != nil || p != 10 {
+ t.Fatalf("want %d got %d, err=%v", 10, p, err)
+ }
+ r.assertSeeked(t, []seekRecord{{10, io.SeekStart}})
+ if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{10, 11, 12, 13, 14}) {
+ t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{10, 11, 12, 13, 14}, got, err)
+ }
+}
+
+type seekRecord struct {
+ offset int64
+ whence int
+}
+
+type seekRecorder struct {
+ rs io.ReadSeeker
+ seeks []seekRecord
+}
+
+func (r *seekRecorder) Read(p []byte) (n int, err error) {
+ return r.rs.Read(p)
+}
+
+func (r *seekRecorder) Seek(offset int64, whence int) (int64, error) {
+ r.seeks = append(r.seeks, seekRecord{offset: offset, whence: whence})
+ return r.rs.Seek(offset, whence)
+}
+
+func (r *seekRecorder) assertSeeked(t *testing.T, expected []seekRecord) {
+ t.Helper()
+
+ if !reflect.DeepEqual(expected, r.seeks) {
+ t.Fatalf("seek mismatch; expected %#v, got %#v", expected, r.seeks)
+ }
+ r.reset()
+}
+
+func (r *seekRecorder) reset() {
+ r.seeks = nil
+}
diff --git a/internal/hashutil/crc16/crc16.go b/internal/hashutil/crc16/crc16.go
new file mode 100755
index 0000000..4e963c6
--- /dev/null
+++ b/internal/hashutil/crc16/crc16.go
@@ -0,0 +1,115 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crc16 implements the 16-bit cyclic redundancy check, or CRC-16,
+// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and
+// http://www.ross.net/crc/download/crc_v3.txt for information.
+package crc16
+
+import "github.com/mewkiz/flac/internal/hashutil"
+
+// Size of a CRC-16 checksum in bytes.
+const Size = 2
+
+// Predefined polynomials.
+const (
+ IBM = 0x8005 // x^16 + x^15 + x^2 + x^0
+)
+
+// Table is a 256-word table representing the polynomial for efficient
+// processing.
+type Table [256]uint16
+
+// IBMTable is the table for the IBM polynomial.
+var IBMTable = makeTable(IBM)
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint16) (table *Table) {
+ switch poly {
+ case IBM:
+ return IBMTable
+ }
+ return makeTable(poly)
+}
+
+// makeTable returns the Table constructed from the specified polynomial.
+func makeTable(poly uint16) (table *Table) {
+ table = new(Table)
+ for i := range table {
+ crc := uint16(i << 8)
+ for j := 0; j < 8; j++ {
+ if crc&0x8000 != 0 {
+ crc = crc<<1 ^ poly
+ } else {
+ crc <<= 1
+ }
+ }
+ table[i] = crc
+ }
+ return table
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint16
+ table *Table
+}
+
+// New creates a new hashutil.Hash16 computing the CRC-16 checksum using the
+// polynomial represented by the Table.
+func New(table *Table) hashutil.Hash16 {
+ return &digest{0, table}
+}
+
+// NewIBM creates a new hashutil.Hash16 computing the CRC-16 checksum using the
+// IBM polynomial.
+func NewIBM() hashutil.Hash16 {
+ return New(IBMTable)
+}
+
+func (d *digest) Size() int {
+ return Size
+}
+
+func (d *digest) BlockSize() int {
+ return 1
+}
+
+func (d *digest) Reset() {
+ d.crc = 0
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint16, table *Table, p []byte) uint16 {
+ for _, v := range p {
+ crc = crc<<8 ^ table[crc>>8^uint16(v)]
+ }
+ return crc
+}
+
+func (d *digest) Write(p []byte) (n int, err error) {
+ d.crc = Update(d.crc, d.table, p)
+ return len(p), nil
+}
+
+// Sum16 returns the 16-bit checksum of the hash.
+func (d *digest) Sum16() uint16 {
+ return d.crc
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ s := d.Sum16()
+ return append(in, byte(s>>8), byte(s))
+}
+
+// Checksum returns the CRC-16 checksum of data, using the polynomial
+// represented by the Table.
+func Checksum(data []byte, table *Table) uint16 {
+ return Update(0, table, data)
+}
+
+// ChecksumIBM returns the CRC-16 checksum of data using the IBM polynomial.
+func ChecksumIBM(data []byte) uint16 {
+ return Update(0, IBMTable, data)
+}
diff --git a/internal/hashutil/crc16/crc16_test.go b/internal/hashutil/crc16/crc16_test.go
new file mode 100755
index 0000000..1741087
--- /dev/null
+++ b/internal/hashutil/crc16/crc16_test.go
@@ -0,0 +1,106 @@
+package crc16
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ want uint16
+ in string
+}
+
+var golden = []test{
+ {0x0000, ""},
+ {0x8145, "a"},
+ {0xC749, "ab"},
+ {0xCADB, "abc"},
+ {0x58E7, "abcd"},
+ {0x678D, "abcde"},
+ {0x0D05, "abcdef"},
+ {0x047C, "abcdefg"},
+ {0x7D68, "abcdefgh"},
+ {0x6878, "abcdefghi"},
+ {0xF80F, "abcdefghij"},
+ {0x0F8E, "Discard medicine more than two years old."},
+ {0xE149, "He who has a shady past knows that nice guys finish last."},
+ {0x02B7, "I wouldn't marry him with a ten foot pole."},
+ {0x7F6A, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x28BD, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x7C55, "Nepal premier won't resign."},
+ {0xC92B, "For every action there is an equal and opposite government program."},
+ {0x3E41, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0xDA56, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0x7F66, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0x2A00, "size: a.out: bad magic"},
+ {0x25B2, "The major problem is with sendmail. -Mark Horton"},
+ {0xBD71, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x8596, "If the enemy is within range, then so are you."},
+ {0x74A2, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x0D73, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xEE65, "C is as portable as Stonehedge!!"},
+ {0xA94E, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0x0B98, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0xF560, "How can you write a big system without C++? -Paul Glick"},
+ {0x60AE, "The quick brown fox jumps over the lazy dog"},
+}
+
+func TestCrc16IBM(t *testing.T) {
+ for _, g := range golden {
+ h := NewIBM()
+ if _, err := io.WriteString(h, g.in); err != nil {
+ t.Error(err)
+ continue
+ }
+ got := h.Sum16()
+ if got != g.want {
+ t.Errorf("IBM(%q); expected 0x%04X, got 0x%04X.", g.in, g.want, got)
+ }
+ }
+}
+
+func BenchmarkNewIBM(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NewIBM()
+ }
+}
+
+func BenchmarkCrc16_1K(b *testing.B) {
+ benchmarkCrc16(b, 1024)
+}
+
+func BenchmarkCrc16_2K(b *testing.B) {
+ benchmarkCrc16(b, 2*1024)
+}
+
+func BenchmarkCrc16_4K(b *testing.B) {
+ benchmarkCrc16(b, 4*1024)
+}
+
+func BenchmarkCrc16_8K(b *testing.B) {
+ benchmarkCrc16(b, 8*1024)
+}
+
+func BenchmarkCrc16_16K(b *testing.B) {
+ benchmarkCrc16(b, 16*1024)
+}
+
+func benchmarkCrc16(b *testing.B, count int64) {
+ b.SetBytes(count)
+ data := make([]byte, count)
+ for i := range data {
+ data[i] = byte(i)
+ }
+ h := NewIBM()
+ in := make([]byte, 0, h.Size())
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ h.Reset()
+ if _, err := h.Write(data); err != nil {
+ b.Error(err)
+ continue
+ }
+ h.Sum(in)
+ }
+}
diff --git a/internal/hashutil/crc8/crc8.go b/internal/hashutil/crc8/crc8.go
new file mode 100755
index 0000000..f701373
--- /dev/null
+++ b/internal/hashutil/crc8/crc8.go
@@ -0,0 +1,114 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crc8 implements the 8-bit cyclic redundancy check, or CRC-8,
+// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and
+// http://www.ross.net/crc/download/crc_v3.txt for information.
+package crc8
+
+import "github.com/mewkiz/flac/internal/hashutil"
+
+// Size of a CRC-8 checksum in bytes.
+const Size = 1
+
+// Predefined polynomials.
+const (
+ ATM = 0x07 // x^8 + x^2 + x + 1
+)
+
+// Table is a 256-word table representing the polynomial for efficient
+// processing.
+type Table [256]uint8
+
+// ATMTable is the table for the ATM polynomial.
+var ATMTable = makeTable(ATM)
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint8) (table *Table) {
+ switch poly {
+ case ATM:
+ return ATMTable
+ }
+ return makeTable(poly)
+}
+
+// makeTable returns the Table constructed from the specified polynomial.
+func makeTable(poly uint8) (table *Table) {
+ table = new(Table)
+ for i := range table {
+ crc := uint8(i)
+ for j := 0; j < 8; j++ {
+ if crc&0x80 != 0 {
+ crc = crc<<1 ^ poly
+ } else {
+ crc <<= 1
+ }
+ }
+ table[i] = crc
+ }
+ return table
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint8
+ table *Table
+}
+
+// New creates a new hashutil.Hash8 computing the CRC-8 checksum using the
+// polynomial represented by the Table.
+func New(table *Table) hashutil.Hash8 {
+ return &digest{0, table}
+}
+
+// NewATM creates a new hashutil.Hash8 computing the CRC-8 checksum using the
+// ATM polynomial.
+func NewATM() hashutil.Hash8 {
+ return New(ATMTable)
+}
+
+func (d *digest) Size() int {
+ return Size
+}
+
+func (d *digest) BlockSize() int {
+ return 1
+}
+
+func (d *digest) Reset() {
+ d.crc = 0
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint8, table *Table, p []byte) uint8 {
+ for _, v := range p {
+ crc = table[crc^v]
+ }
+ return crc
+}
+
+func (d *digest) Write(p []byte) (n int, err error) {
+ d.crc = Update(d.crc, d.table, p)
+ return len(p), nil
+}
+
+// Sum8 returns the 8-bit checksum of the hash.
+func (d *digest) Sum8() uint8 {
+ return d.crc
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ return append(in, d.crc)
+}
+
+// Checksum returns the CRC-8 checksum of data, using the polynomial represented
+// by the Table.
+func Checksum(data []byte, table *Table) uint8 {
+ return Update(0, table, data)
+}
+
+// ChecksumATM returns the CRC-8 checksum of data using the ATM polynomial.
+func ChecksumATM(data []byte) uint8 {
+ return Update(0, ATMTable, data)
+}
diff --git a/internal/hashutil/crc8/crc8_test.go b/internal/hashutil/crc8/crc8_test.go
new file mode 100755
index 0000000..5e639ab
--- /dev/null
+++ b/internal/hashutil/crc8/crc8_test.go
@@ -0,0 +1,106 @@
+package crc8
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ want uint8
+ in string
+}
+
+var golden = []test{
+ {0x00, ""},
+ {0x20, "a"},
+ {0xC9, "ab"},
+ {0x5F, "abc"},
+ {0xA1, "abcd"},
+ {0x52, "abcde"},
+ {0x8C, "abcdef"},
+ {0x9F, "abcdefg"},
+ {0xCB, "abcdefgh"},
+ {0x67, "abcdefghi"},
+ {0x23, "abcdefghij"},
+ {0x56, "Discard medicine more than two years old."},
+ {0x6B, "He who has a shady past knows that nice guys finish last."},
+ {0x70, "I wouldn't marry him with a ten foot pole."},
+ {0x8F, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x48, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x5E, "Nepal premier won't resign."},
+ {0x3C, "For every action there is an equal and opposite government program."},
+ {0xA8, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x46, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xC7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0x31, "size: a.out: bad magic"},
+ {0xB6, "The major problem is with sendmail. -Mark Horton"},
+ {0x7D, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0xDC, "If the enemy is within range, then so are you."},
+ {0x13, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x96, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0x96, "C is as portable as Stonehedge!!"},
+ {0x3C, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xEE, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x33, "How can you write a big system without C++? -Paul Glick"},
+ {0xC1, "The quick brown fox jumps over the lazy dog"},
+}
+
+func TestCrc8ATM(t *testing.T) {
+ for _, g := range golden {
+ h := NewATM()
+ if _, err := io.WriteString(h, g.in); err != nil {
+ t.Error(err)
+ continue
+ }
+ got := h.Sum8()
+ if got != g.want {
+ t.Errorf("ATM(%q); expected 0x%02X, got 0x%02X.", g.in, g.want, got)
+ }
+ }
+}
+
+func BenchmarkNewATM(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NewATM()
+ }
+}
+
+func BenchmarkCrc8_1K(b *testing.B) {
+ benchmarkCrc8(b, 1024)
+}
+
+func BenchmarkCrc8_2K(b *testing.B) {
+ benchmarkCrc8(b, 2*1024)
+}
+
+func BenchmarkCrc8_4K(b *testing.B) {
+ benchmarkCrc8(b, 4*1024)
+}
+
+func BenchmarkCrc8_8K(b *testing.B) {
+ benchmarkCrc8(b, 8*1024)
+}
+
+func BenchmarkCrc8_16K(b *testing.B) {
+ benchmarkCrc8(b, 16*1024)
+}
+
+func benchmarkCrc8(b *testing.B, count int64) {
+ b.SetBytes(count)
+ data := make([]byte, count)
+ for i := range data {
+ data[i] = byte(i)
+ }
+ h := NewATM()
+ in := make([]byte, 0, h.Size())
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ h.Reset()
+ if _, err := h.Write(data); err != nil {
+ b.Error(err)
+ continue
+ }
+ h.Sum(in)
+ }
+}
diff --git a/internal/hashutil/hashutil.go b/internal/hashutil/hashutil.go
new file mode 100755
index 0000000..5976032
--- /dev/null
+++ b/internal/hashutil/hashutil.go
@@ -0,0 +1,18 @@
+// Package hashutil provides utility interfaces for hash functions.
+package hashutil
+
+import "hash"
+
+// Hash8 is the common interface implemented by all 8-bit hash functions.
+type Hash8 interface {
+ hash.Hash
+ // Sum8 returns the 8-bit checksum of the hash.
+ Sum8() uint8
+}
+
+// Hash16 is the common interface implemented by all 16-bit hash functions.
+type Hash16 interface {
+ hash.Hash
+ // Sum16 returns the 16-bit checksum of the hash.
+ Sum16() uint16
+}
diff --git a/internal/ioutilx/byte.go b/internal/ioutilx/byte.go
new file mode 100755
index 0000000..33b9dd0
--- /dev/null
+++ b/internal/ioutilx/byte.go
@@ -0,0 +1,24 @@
+// Package ioutilx implements extended input/output utility functions.
+package ioutilx
+
+import (
+ "io"
+)
+
+// ReadByte reads and returns the next byte from r.
+func ReadByte(r io.Reader) (byte, error) {
+ var buf [1]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
+ return 0, err
+ }
+ return buf[0], nil
+}
+
+// WriteByte writes the given byte to w.
+func WriteByte(w io.Writer, b byte) error {
+ buf := [1]byte{b}
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/internal/ioutilx/zero.go b/internal/ioutilx/zero.go
new file mode 100755
index 0000000..bdd9a14
--- /dev/null
+++ b/internal/ioutilx/zero.go
@@ -0,0 +1,17 @@
+package ioutilx
+
+// Zero is an io.Reader which always reads zero bytes.
+var Zero zero
+
+// zero is an io.Reader which always reads zero bytes.
+type zero struct {
+}
+
+// Read reads len(b) zero bytes into b. It returns the number of bytes read and
+// a nil error value.
+func (zero) Read(b []byte) (n int, err error) {
+ for i := range b {
+ b[i] = 0
+ }
+ return len(b), nil
+}
diff --git a/internal/utf8/decode.go b/internal/utf8/decode.go
new file mode 100755
index 0000000..ce7fde5
--- /dev/null
+++ b/internal/utf8/decode.go
@@ -0,0 +1,160 @@
+// Package utf8 implements encoding and decoding of UTF-8 coded numbers.
+package utf8
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/mewkiz/flac/internal/ioutilx"
+)
+
+const (
+ tx = 0x80 // 1000 0000
+ t2 = 0xC0 // 1100 0000
+ t3 = 0xE0 // 1110 0000
+ t4 = 0xF0 // 1111 0000
+ t5 = 0xF8 // 1111 1000
+ t6 = 0xFC // 1111 1100
+ t7 = 0xFE // 1111 1110
+ t8 = 0xFF // 1111 1111
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+ mask5 = 0x03 // 0000 0011
+ mask6 = 0x01 // 0000 0001
+
+ rune1Max = 1<<7 - 1
+ rune2Max = 1<<11 - 1
+ rune3Max = 1<<16 - 1
+ rune4Max = 1<<21 - 1
+ rune5Max = 1<<26 - 1
+ rune6Max = 1<<31 - 1
+ rune7Max = 1<<36 - 1
+)
+
+// Decode decodes a "UTF-8" coded number and returns it.
+//
+// ref: http://permalink.gmane.org/gmane.comp.audio.compression.flac.devel/3033
+//
+// Algorithm description:
+// - read one byte B0 from the stream
+// - if B0 = 0xxxxxxx then the read value is B0 -> end
+// - if B0 = 10xxxxxx, the encoding is invalid
+// - if B0 = 11xxxxxx, set L to the number of leading binary 1s minus 1:
+// B0 = 110xxxxx -> L = 1
+// B0 = 1110xxxx -> L = 2
+// B0 = 11110xxx -> L = 3
+// B0 = 111110xx -> L = 4
+// B0 = 1111110x -> L = 5
+// B0 = 11111110 -> L = 6
+// - assign the bits following the encoding (the x bits in the examples) to
+// a variable R with a magnitude of at least 36 bits
+// - loop from 1 to L
+// - left shift R 6 bits
+// - read B from the stream
+// - if B does not match 10xxxxxx, the encoding is invalid
+// - set R = R or
+// - the read value is R
+func Decode(r io.Reader) (x uint64, err error) {
+ c0, err := ioutilx.ReadByte(r)
+ if err != nil {
+ return 0, err
+ }
+
+ // 1-byte, 7-bit sequence?
+ if c0 < tx {
+ // if c0 == 0xxxxxxx
+ // total: 7 bits (7)
+ return uint64(c0), nil
+ }
+
+ // unexpected continuation byte?
+ if c0 < t2 {
+ // if c0 == 10xxxxxx
+ return 0, errors.New("frame.decodeUTF8Int: unexpected continuation byte")
+ }
+
+ // get number of continuation bytes and store bits from c0.
+ var l int
+ switch {
+ case c0 < t3:
+ // if c0 == 110xxxxx
+ // total: 11 bits (5 + 6)
+ l = 1
+ x = uint64(c0 & mask2)
+ case c0 < t4:
+ // if c0 == 1110xxxx
+ // total: 16 bits (4 + 6 + 6)
+ l = 2
+ x = uint64(c0 & mask3)
+ case c0 < t5:
+ // if c0 == 11110xxx
+ // total: 21 bits (3 + 6 + 6 + 6)
+ l = 3
+ x = uint64(c0 & mask4)
+ case c0 < t6:
+ // if c0 == 111110xx
+ // total: 26 bits (2 + 6 + 6 + 6 + 6)
+ l = 4
+ x = uint64(c0 & mask5)
+ case c0 < t7:
+ // if c0 == 1111110x
+ // total: 31 bits (1 + 6 + 6 + 6 + 6 + 6)
+ l = 5
+ x = uint64(c0 & mask6)
+ case c0 < t8:
+ // if c0 == 11111110
+ // total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6)
+ l = 6
+ x = 0
+ }
+
+ // store bits from continuation bytes.
+ for i := 0; i < l; i++ {
+ x <<= 6
+ c, err := ioutilx.ReadByte(r)
+ if err != nil {
+ if err == io.EOF {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ if c < tx || t2 <= c {
+ // if c != 10xxxxxx
+ return 0, errors.New("frame.decodeUTF8Int: expected continuation byte")
+ }
+ x |= uint64(c & maskx)
+ }
+
+ // check if number representation is larger than necessary.
+ switch l {
+ case 1:
+ if x <= rune1Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ case 2:
+ if x <= rune2Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ case 3:
+ if x <= rune3Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ case 4:
+ if x <= rune4Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ case 5:
+ if x <= rune5Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ case 6:
+ if x <= rune6Max {
+ return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
+ }
+ }
+ return x, nil
+}
diff --git a/internal/utf8/encode.go b/internal/utf8/encode.go
new file mode 100755
index 0000000..43f263b
--- /dev/null
+++ b/internal/utf8/encode.go
@@ -0,0 +1,72 @@
+package utf8
+
+import (
+ "io"
+
+ "github.com/mewkiz/flac/internal/ioutilx"
+ "github.com/mewkiz/pkg/errutil"
+)
+
+// Encode encodes x as a "UTF-8" coded number.
+func Encode(w io.Writer, x uint64) error {
+ // 1-byte, 7-bit sequence?
+ if x <= rune1Max {
+ if err := ioutilx.WriteByte(w, byte(x)); err != nil {
+ return errutil.Err(err)
+ }
+ return nil
+ }
+
+ // get number of continuation bytes and store bits of c0.
+ var (
+ // number of continuation bytes.,
+ l int
+ // bits of c0.
+ bits uint64
+ )
+ switch {
+ case x <= rune2Max:
+ // if c0 == 110xxxxx
+ // total: 11 bits (5 + 6)
+ l = 1
+ bits = t2 | (x>>6)&mask2
+ case x <= rune3Max:
+ // if c0 == 1110xxxx
+ // total: 16 bits (4 + 6 + 6)
+ l = 2
+ bits = t3 | (x>>(6*2))&mask3
+ case x <= rune4Max:
+ // if c0 == 11110xxx
+ // total: 21 bits (3 + 6 + 6 + 6)
+ l = 3
+ bits = t4 | (x>>(6*3))&mask4
+ case x <= rune5Max:
+ // if c0 == 111110xx
+ // total: 26 bits (2 + 6 + 6 + 6 + 6)
+ l = 4
+ bits = t5 | (x>>(6*4))&mask5
+ case x <= rune6Max:
+ // if c0 == 1111110x
+ // total: 31 bits (1 + 6 + 6 + 6 + 6 + 6)
+ l = 5
+ bits = t6 | (x>>(6*5))&mask6
+ case x <= rune7Max:
+ // if c0 == 11111110
+ // total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6)
+ l = 6
+ bits = 0
+ }
+ // Store bits of c0.
+ if err := ioutilx.WriteByte(w, byte(bits)); err != nil {
+ return errutil.Err(err)
+ }
+
+ // Store continuation bytes.
+ for i := l - 1; i >= 0; i-- {
+ bits := tx | (x>>uint(6*i))&maskx
+ if err := ioutilx.WriteByte(w, byte(bits)); err != nil {
+ return errutil.Err(err)
+ }
+ }
+ return nil
+}
diff --git a/meta/application.go b/meta/application.go
new file mode 100755
index 0000000..6f5a2e2
--- /dev/null
+++ b/meta/application.go
@@ -0,0 +1,38 @@
+package meta
+
+import (
+ "encoding/binary"
+ "io/ioutil"
+)
+
+// Application contains third party application specific data.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_application
+type Application struct {
+ // Registered application ID.
+ //
+ // ref: https://www.xiph.org/flac/id.html
+ ID uint32
+ // Application data.
+ Data []byte
+}
+
+// parseApplication reads and parses the body of an Application metadata block.
+func (block *Block) parseApplication() error {
+ // 32 bits: ID.
+ app := new(Application)
+ block.Body = app
+ err := binary.Read(block.lr, binary.BigEndian, &app.ID)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // Check if the Application block only contains an ID.
+ if block.Length == 4 {
+ return nil
+ }
+
+ // (block length)-4 bytes: Data.
+ app.Data, err = ioutil.ReadAll(block.lr)
+ return unexpected(err)
+}
diff --git a/meta/cuesheet.go b/meta/cuesheet.go
new file mode 100755
index 0000000..d066267
--- /dev/null
+++ b/meta/cuesheet.go
@@ -0,0 +1,242 @@
+package meta
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+)
+
+// A CueSheet describes how tracks are laid out within a FLAC stream.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_cuesheet
+type CueSheet struct {
+ // Media catalog number.
+ MCN string
+ // Number of lead-in samples. This field only has meaning for CD-DA cue
+ // sheets; for other uses it should be 0. Refer to the spec for additional
+ // information.
+ NLeadInSamples uint64
+ // Specifies if the cue sheet corresponds to a Compact Disc.
+ IsCompactDisc bool
+ // One or more tracks. The last track of a cue sheet is always the lead-out
+ // track.
+ Tracks []CueSheetTrack
+}
+
+// parseCueSheet reads and parses the body of a CueSheet metadata block.
+func (block *Block) parseCueSheet() error {
+ // Parse cue sheet.
+ // 128 bytes: MCN.
+ szMCN, err := readString(block.lr, 128)
+ if err != nil {
+ return unexpected(err)
+ }
+ cs := &CueSheet{
+ MCN: stringFromSZ(szMCN),
+ }
+ block.Body = cs
+
+ // 64 bits: NLeadInSamples.
+ if err = binary.Read(block.lr, binary.BigEndian, &cs.NLeadInSamples); err != nil {
+ return unexpected(err)
+ }
+
+ // 1 bit: IsCompactDisc.
+ var x uint8
+ if err := binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ // mask = 10000000
+ if x&0x80 != 0 {
+ cs.IsCompactDisc = true
+ }
+
+ // 7 bits and 258 bytes: reserved.
+ // mask = 01111111
+ if x&0x7F != 0 {
+ return ErrInvalidPadding
+ }
+ lr := io.LimitReader(block.lr, 258)
+ zr := zeros{r: lr}
+ if _, err := io.Copy(ioutil.Discard, zr); err != nil {
+ return err
+ }
+
+ // Parse cue sheet tracks.
+ // 8 bits: (number of tracks)
+ if err := binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ if x < 1 {
+ return errors.New("meta.Block.parseCueSheet: at least one track required")
+ }
+ if cs.IsCompactDisc && x > 100 {
+ return fmt.Errorf("meta.Block.parseCueSheet: number of CD-DA tracks (%d) exceeds 100", x)
+ }
+ cs.Tracks = make([]CueSheetTrack, x)
+ // Each track number within a cue sheet must be unique; use uniq to keep
+ // track.
+ uniq := make(map[uint8]struct{})
+ for i := range cs.Tracks {
+ if err := block.parseTrack(cs, i, uniq); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// parseTrack parses the i:th cue sheet track, and ensures that its track number
+// is unique.
+func (block *Block) parseTrack(cs *CueSheet, i int, uniq map[uint8]struct{}) error {
+ track := &cs.Tracks[i]
+ // 64 bits: Offset.
+ if err := binary.Read(block.lr, binary.BigEndian, &track.Offset); err != nil {
+ return unexpected(err)
+ }
+ if cs.IsCompactDisc && track.Offset%588 != 0 {
+ return fmt.Errorf("meta.Block.parseCueSheet: CD-DA track offset (%d) must be evenly divisible by 588", track.Offset)
+ }
+
+ // 8 bits: Num.
+ if err := binary.Read(block.lr, binary.BigEndian, &track.Num); err != nil {
+ return unexpected(err)
+ }
+ if _, ok := uniq[track.Num]; ok {
+ return fmt.Errorf("meta.Block.parseCueSheet: duplicated track number %d", track.Num)
+ }
+ uniq[track.Num] = struct{}{}
+ if track.Num == 0 {
+ return errors.New("meta.Block.parseCueSheet: invalid track number (0)")
+ }
+ isLeadOut := i == len(cs.Tracks)-1
+ if cs.IsCompactDisc {
+ if !isLeadOut {
+ if track.Num >= 100 {
+ return fmt.Errorf("meta.Block.parseCueSheet: CD-DA track number (%d) exceeds 99", track.Num)
+ }
+ } else {
+ if track.Num != 170 {
+ return fmt.Errorf("meta.Block.parseCueSheet: invalid lead-out CD-DA track number; expected 170, got %d", track.Num)
+ }
+ }
+ } else {
+ if isLeadOut && track.Num != 255 {
+ return fmt.Errorf("meta.Block.parseCueSheet: invalid lead-out track number; expected 255, got %d", track.Num)
+ }
+ }
+
+ // 12 bytes: ISRC.
+ szISRC, err := readString(block.lr, 12)
+ if err != nil {
+ return unexpected(err)
+ }
+ track.ISRC = stringFromSZ(szISRC)
+
+ // 1 bit: IsAudio.
+ var x uint8
+ if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ // mask = 10000000
+ if x&0x80 == 0 {
+ track.IsAudio = true
+ }
+
+ // 1 bit: HasPreEmphasis.
+ // mask = 01000000
+ if x&0x40 != 0 {
+ track.HasPreEmphasis = true
+ }
+
+ // 6 bits and 13 bytes: reserved.
+ // mask = 00111111
+ if x&0x3F != 0 {
+ return ErrInvalidPadding
+ }
+ lr := io.LimitReader(block.lr, 13)
+ zr := zeros{r: lr}
+ _, err = io.Copy(ioutil.Discard, zr)
+ if err != nil {
+ return err
+ }
+
+ // Parse indicies.
+ // 8 bits: (number of indicies)
+ if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ if x < 1 {
+ if !isLeadOut {
+ return errors.New("meta.Block.parseCueSheet: at least one track index required")
+ }
+ // Lead-out track has no track indices to parse; return early.
+ return nil
+ }
+ track.Indicies = make([]CueSheetTrackIndex, x)
+ for i := range track.Indicies {
+ index := &track.Indicies[i]
+ // 64 bits: Offset.
+ if err = binary.Read(block.lr, binary.BigEndian, &index.Offset); err != nil {
+ return unexpected(err)
+ }
+
+ // 8 bits: Num.
+ if err = binary.Read(block.lr, binary.BigEndian, &index.Num); err != nil {
+ return unexpected(err)
+ }
+
+ // 3 bytes: reserved.
+ lr = io.LimitReader(block.lr, 3)
+ zr = zeros{r: lr}
+ _, err = io.Copy(ioutil.Discard, zr)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// stringFromSZ returns a copy of the given string terminated at the first
+// occurrence of a NULL character.
+func stringFromSZ(szStr string) string {
+ pos := strings.IndexByte(szStr, '\x00')
+ if pos == -1 {
+ return szStr
+ }
+ return string(szStr[:pos])
+}
+
+// CueSheetTrack contains the start offset of a track and other track specific
+// metadata.
+type CueSheetTrack struct {
+ // Track offset in samples, relative to the beginning of the FLAC audio
+ // stream.
+ Offset uint64
+ // Track number; never 0, always unique.
+ Num uint8
+ // International Standard Recording Code; empty string if not present.
+ //
+ // ref: http://isrc.ifpi.org/
+ ISRC string
+ // Specifies if the track contains audio or data.
+ IsAudio bool
+ // Specifies if the track has been recorded with pre-emphasis
+ HasPreEmphasis bool
+ // Every track has one or more track index points, except for the lead-out
+ // track which has zero. Each index point specifies a position within the
+ // track.
+ Indicies []CueSheetTrackIndex
+}
+
+// A CueSheetTrackIndex specifies a position within a track.
+type CueSheetTrackIndex struct {
+ // Index point offset in samples, relative to the track offset.
+ Offset uint64
+ // Index point number; subsequently incrementing by 1 and always unique
+ // within a track.
+ Num uint8
+}
diff --git a/meta/meta.go b/meta/meta.go
new file mode 100755
index 0000000..9f91db2
--- /dev/null
+++ b/meta/meta.go
@@ -0,0 +1,210 @@
+// Package meta implements access to FLAC metadata blocks.
+//
+// A brief introduction of the FLAC metadata format [1] follows. FLAC metadata
+// is stored in blocks; each block contains a header followed by a body. The
+// block header describes the type of the block body, its length in bytes, and
+// specifies if the block was the last metadata block in a FLAC stream. The
+// contents of the block body depends on the type specified in the block header.
+//
+// At the time of this writing, the FLAC metadata format defines seven different
+// metadata block types, namely:
+// - StreamInfo [2]
+// - Padding [3]
+// - Application [4]
+// - SeekTable [5]
+// - VorbisComment [6]
+// - CueSheet [7]
+// - Picture [8]
+//
+// Please refer to their respective documentation for further information.
+//
+// [1]: https://www.xiph.org/flac/format.html#format_overview
+// [2]: https://godoc.org/github.com/mewkiz/flac/meta#StreamInfo
+// [3]: https://www.xiph.org/flac/format.html#metadata_block_padding
+// [4]: https://godoc.org/github.com/mewkiz/flac/meta#Application
+// [5]: https://godoc.org/github.com/mewkiz/flac/meta#SeekTable
+// [6]: https://godoc.org/github.com/mewkiz/flac/meta#VorbisComment
+// [7]: https://godoc.org/github.com/mewkiz/flac/meta#CueSheet
+// [8]: https://godoc.org/github.com/mewkiz/flac/meta#Picture
+package meta
+
+import (
+ "errors"
+ "io"
+ "io/ioutil"
+
+ "github.com/mewkiz/flac/internal/bits"
+)
+
+// A Block contains the header and body of a metadata block.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block
+type Block struct {
+ // Metadata block header.
+ Header
+ // Metadata block body of type *StreamInfo, *Application, ... etc. Body is
+ // initially nil, and gets populated by a call to Block.Parse.
+ Body interface{}
+ // Underlying io.Reader; limited by the length of the block body.
+ lr io.Reader
+}
+
+// New creates a new Block for accessing the metadata of r. It reads and parses
+// a metadata block header.
+//
+// Call Block.Parse to parse the metadata block body, and call Block.Skip to
+// ignore it.
+func New(r io.Reader) (block *Block, err error) {
+ block = new(Block)
+ if err = block.parseHeader(r); err != nil {
+ return block, err
+ }
+ block.lr = io.LimitReader(r, block.Length)
+ return block, nil
+}
+
+// Parse reads and parses the header and body of a metadata block. Use New for
+// additional granularity.
+func Parse(r io.Reader) (block *Block, err error) {
+ block, err = New(r)
+ if err != nil {
+ return block, err
+ }
+ if err = block.Parse(); err != nil {
+ return block, err
+ }
+ return block, nil
+}
+
+// Errors returned by Parse.
+var (
+ ErrReservedType = errors.New("meta.Block.Parse: reserved block type")
+ ErrInvalidType = errors.New("meta.Block.Parse: invalid block type")
+)
+
+// Parse reads and parses the metadata block body.
+func (block *Block) Parse() error {
+ switch block.Type {
+ case TypeStreamInfo:
+ return block.parseStreamInfo()
+ case TypePadding:
+ return block.verifyPadding()
+ case TypeApplication:
+ return block.parseApplication()
+ case TypeSeekTable:
+ return block.parseSeekTable()
+ case TypeVorbisComment:
+ return block.parseVorbisComment()
+ case TypeCueSheet:
+ return block.parseCueSheet()
+ case TypePicture:
+ return block.parsePicture()
+ }
+ if block.Type >= 7 && block.Type <= 126 {
+ return ErrReservedType
+ }
+ return ErrInvalidType
+}
+
+// Skip ignores the contents of the metadata block body.
+func (block *Block) Skip() error {
+ if sr, ok := block.lr.(io.Seeker); ok {
+ _, err := sr.Seek(0, io.SeekEnd)
+ return err
+ }
+ _, err := io.Copy(ioutil.Discard, block.lr)
+ return err
+}
+
+// A Header contains information about the type and length of a metadata block.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_header
+type Header struct {
+ // Metadata block body type.
+ Type Type
+ // Length of body data in bytes.
+ Length int64
+ // IsLast specifies if the block is the last metadata block.
+ IsLast bool
+}
+
+// parseHeader reads and parses the header of a metadata block.
+func (block *Block) parseHeader(r io.Reader) error {
+ // 1 bit: IsLast.
+ br := bits.NewReader(r)
+ x, err := br.Read(1)
+ if err != nil {
+ // This is the only place a metadata block may return io.EOF, which
+ // signals a graceful end of a FLAC stream (from a metadata point of
+ // view).
+ //
+ // Note that valid FLAC streams always contain at least one audio frame
+ // after the last metadata block. Therefore an io.EOF error at this
+ // location is always invalid. This logic is to be handled by the flac
+ // package however.
+ return err
+ }
+ if x != 0 {
+ block.IsLast = true
+ }
+
+ // 7 bits: Type.
+ x, err = br.Read(7)
+ if err != nil {
+ return unexpected(err)
+ }
+ block.Type = Type(x)
+
+ // 24 bits: Length.
+ x, err = br.Read(24)
+ if err != nil {
+ return unexpected(err)
+ }
+ block.Length = int64(x)
+
+ return nil
+}
+
+// Type represents the type of a metadata block body.
+type Type uint8
+
+// Metadata block body types.
+const (
+ TypeStreamInfo Type = 0
+ TypePadding Type = 1
+ TypeApplication Type = 2
+ TypeSeekTable Type = 3
+ TypeVorbisComment Type = 4
+ TypeCueSheet Type = 5
+ TypePicture Type = 6
+)
+
+func (t Type) String() string {
+ switch t {
+ case TypeStreamInfo:
+ return "stream info"
+ case TypePadding:
+ return "padding"
+ case TypeApplication:
+ return "application"
+ case TypeSeekTable:
+ return "seek table"
+ case TypeVorbisComment:
+ return "vorbis comment"
+ case TypeCueSheet:
+ return "cue sheet"
+ case TypePicture:
+ return "picture"
+ default:
+ return ""
+ }
+}
+
+// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err
+// otherwise.
+func unexpected(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/meta/meta_test.go b/meta/meta_test.go
new file mode 100755
index 0000000..268e63a
--- /dev/null
+++ b/meta/meta_test.go
@@ -0,0 +1,260 @@
+package meta_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "reflect"
+ "testing"
+
+ "github.com/mewkiz/flac"
+ "github.com/mewkiz/flac/meta"
+)
+
+var golden = []struct {
+ path string
+ info *meta.StreamInfo
+ blocks []*meta.Block
+}{
+ {
+ path: "../testdata/59996.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1000, BlockSizeMax: 0x1000, FrameSizeMin: 0x44c5, FrameSizeMax: 0x4588, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x18, NSamples: 0x2000, MD5sum: [16]uint8{0x95, 0xba, 0xe5, 0xe2, 0xc7, 0x45, 0xbb, 0x3c, 0xa9, 0x5c, 0xa3, 0xb1, 0x35, 0xc9, 0x43, 0xf4}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x4, Length: 202, IsLast: true},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: [][2]string{{"Description", "Waving a bamboo staff"}, {"YEAR", "2008"}, {"ARTIST", "qubodup aka Iwan Gabovitch | qubodup@gmail.com"}, {"COMMENTS", "I release this file into the public domain"}}},
+ },
+ },
+ },
+ {
+ path: "../testdata/172960.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1000, BlockSizeMax: 0x1000, FrameSizeMin: 0xb7c, FrameSizeMax: 0x256b, SampleRate: 0x17700, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0xaaa3, MD5sum: [16]uint8{0x76, 0x3d, 0xa8, 0xa5, 0xb7, 0x58, 0xe6, 0x2, 0x61, 0xb4, 0xd4, 0xc2, 0x88, 0x4d, 0x8e, 0xe}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x4, Length: 180, IsLast: true},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: [][2]string{{"GENRE", "Sound Clip"}, {"ARTIST", "Iwan 'qubodup' Gabovitch"}, {"Artist Homepage", "http://qubodup.net"}, {"Artist Email", "qubodup@gmail.com"}, {"DATE", "2012"}}},
+ },
+ },
+ },
+ {
+ path: "../testdata/189983.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0x94d, FrameSizeMax: 0x264a, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x50f4, MD5sum: [16]uint8{0x63, 0x28, 0xed, 0x6d, 0xd3, 0xe, 0x55, 0xfb, 0xa5, 0x73, 0x69, 0x2b, 0xb7, 0x35, 0x73, 0xb7}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x4, Length: 40, IsLast: true},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: nil},
+ },
+ },
+ },
+ {
+ path: "testdata/input-SCPAP.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x3, Length: 180, IsLast: false},
+ Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}},
+ },
+ {
+ Header: meta.Header{Type: 0x5, Length: 540, IsLast: false},
+ Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}},
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 4, IsLast: false},
+ Body: nil,
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: false},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true},
+ Body: nil,
+ },
+ },
+ },
+ {
+ path: "testdata/input-SCVA.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x3, Length: 180, IsLast: false},
+ Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}},
+ },
+ {
+ Header: meta.Header{Type: 0x5, Length: 540, IsLast: false},
+ Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}},
+ },
+ {
+ Header: meta.Header{Type: 0x4, Length: 203, IsLast: false},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}},
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: true},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ },
+ },
+ {
+ path: "testdata/input-SCVAUP.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x3, Length: 180, IsLast: false},
+ Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}},
+ },
+ {
+ Header: meta.Header{Type: 0x5, Length: 540, IsLast: false},
+ Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}},
+ },
+ {
+ Header: meta.Header{Type: 0x4, Length: 203, IsLast: false},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}},
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: false},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ {
+ Header: meta.Header{Type: 0x7e, Length: 0, IsLast: false},
+ Body: nil,
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true},
+ Body: nil,
+ },
+ },
+ },
+ {
+ path: "testdata/input-SCVPAP.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x3, Length: 180, IsLast: false},
+ Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}},
+ },
+ {
+ Header: meta.Header{Type: 0x5, Length: 540, IsLast: false},
+ Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}},
+ },
+ {
+ Header: meta.Header{Type: 0x4, Length: 203, IsLast: false},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}},
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 4, IsLast: false},
+ Body: nil,
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: false},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true},
+ Body: nil,
+ },
+ },
+ },
+ {
+ path: "testdata/input-SVAUP.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x3, Length: 180, IsLast: false},
+ Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}},
+ },
+ {
+ Header: meta.Header{Type: 0x4, Length: 203, IsLast: false},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}},
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: false},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ {
+ Header: meta.Header{Type: 0x7e, Length: 0, IsLast: false},
+ Body: nil,
+ },
+ {
+ Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true},
+ Body: nil,
+ },
+ },
+ },
+ {
+ path: "testdata/input-VA.flac",
+ info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}},
+ blocks: []*meta.Block{
+ {
+ Header: meta.Header{Type: 0x4, Length: 203, IsLast: false},
+ Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}},
+ },
+ {
+ Header: meta.Header{Type: 0x2, Length: 4, IsLast: true},
+ Body: &meta.Application{ID: 0x66616b65, Data: nil},
+ },
+ },
+ },
+}
+
+func TestParseBlocks(t *testing.T) {
+ for _, g := range golden {
+ stream, err := flac.ParseFile(g.path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stream.Close()
+ blocks := stream.Blocks
+
+ if len(blocks) != len(g.blocks) {
+ t.Errorf("path=%q: invalid number of metadata blocks; expected %d, got %d", g.path, len(g.blocks), len(blocks))
+ continue
+ }
+
+ got := stream.Info
+ want := g.info
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("path=%q: metadata StreamInfo block bodies differ; expected %#v, got %#v", g.path, want, got)
+ }
+
+ for blockNum, got := range blocks {
+ want := g.blocks[blockNum]
+ if !reflect.DeepEqual(got.Header, want.Header) {
+ t.Errorf("path=%q, blockNum=%d: metadata block headers differ; expected %#v, got %#v", g.path, blockNum, want.Header, got.Header)
+ }
+ if !reflect.DeepEqual(got.Body, want.Body) {
+ t.Errorf("path=%q, blockNum=%d: metadata block bodies differ; expected %#v, got %#v", g.path, blockNum, want.Body, got.Body)
+ }
+ }
+ }
+}
+
+func TestParsePicture(t *testing.T) {
+ stream, err := flac.ParseFile("testdata/silence.flac")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stream.Close()
+
+ want, err := ioutil.ReadFile("testdata/silence.jpg")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, block := range stream.Blocks {
+ if block.Type == meta.TypePicture {
+ pic := block.Body.(*meta.Picture)
+ got := pic.Data
+ if !bytes.Equal(got, want) {
+ t.Errorf("picture data differ; expected %v, got %v", want, got)
+ }
+ break
+ }
+ }
+}
+
+// TODO: better error verification than string-based comparisons.
+func TestMissingValue(t *testing.T) {
+ _, err := flac.ParseFile("testdata/missing-value.flac")
+ if err.Error() != `meta.Block.parseVorbisComment: unable to locate '=' in vector "title 2"` {
+ t.Fatal(err)
+ }
+}
diff --git a/meta/padding.go b/meta/padding.go
new file mode 100755
index 0000000..0d66fa3
--- /dev/null
+++ b/meta/padding.go
@@ -0,0 +1,39 @@
+package meta
+
+import (
+ "errors"
+ "io"
+ "io/ioutil"
+)
+
+// verifyPadding verifies the body of a Padding metadata block. It should only
+// contain zero-padding.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_padding
+func (block *Block) verifyPadding() error {
+ zr := zeros{r: block.lr}
+ _, err := io.Copy(ioutil.Discard, zr)
+ return err
+}
+
+// Errors returned by zeros.Read.
+var (
+ ErrInvalidPadding = errors.New("invalid padding")
+)
+
+// zeros implements an io.Reader, with a Read method which returns an error if
+// any byte read isn't zero.
+type zeros struct {
+ r io.Reader
+}
+
+// Read returns an error if any byte read isn't zero.
+func (zr zeros) Read(p []byte) (n int, err error) {
+ n, err = zr.r.Read(p)
+ for i := 0; i < n; i++ {
+ if p[i] != 0 {
+ return n, ErrInvalidPadding
+ }
+ }
+ return n, err
+}
diff --git a/meta/picture.go b/meta/picture.go
new file mode 100755
index 0000000..5c52d8a
--- /dev/null
+++ b/meta/picture.go
@@ -0,0 +1,120 @@
+package meta
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+// Picture contains the image data of an embedded picture.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_picture
+type Picture struct {
+ // Picture type according to the ID3v2 APIC frame:
+ //
+ // 0: Other
+ // 1: 32x32 pixels 'file icon' (PNG only)
+ // 2: Other file icon
+ // 3: Cover (front)
+ // 4: Cover (back)
+ // 5: Leaflet page
+ // 6: Media (e.g. label side of CD)
+ // 7: Lead artist/lead performer/soloist
+ // 8: Artist/performer
+ // 9: Conductor
+ // 10: Band/Orchestra
+ // 11: Composer
+ // 12: Lyricist/text writer
+ // 13: Recording Location
+ // 14: During recording
+ // 15: During performance
+ // 16: Movie/video screen capture
+ // 17: A bright coloured fish
+ // 18: Illustration
+ // 19: Band/artist logotype
+ // 20: Publisher/Studio logotype
+ //
+ // ref: http://id3.org/id3v2.4.0-frames
+ Type uint32
+ // MIME type string. The MIME type "-->" specifies that the picture data is
+ // to be interpreted as an URL instead of image data.
+ MIME string
+ // Description of the picture.
+ Desc string
+ // Image dimensions.
+ Width, Height uint32
+ // Color depth in bits-per-pixel.
+ Depth uint32
+ // Number of colors in palette; 0 for non-indexed images.
+ NPalColors uint32
+ // Image data.
+ Data []byte
+}
+
+// parsePicture reads and parses the body of a Picture metadata block.
+func (block *Block) parsePicture() error {
+ // 32 bits: Type.
+ pic := new(Picture)
+ block.Body = pic
+ err := binary.Read(block.lr, binary.BigEndian, &pic.Type)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // 32 bits: (MIME type length).
+ var x uint32
+ if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+
+ // (MIME type length) bytes: MIME.
+ mime, err := readString(block.lr, int(x))
+ if err != nil {
+ return unexpected(err)
+ }
+ pic.MIME = mime
+
+ // 32 bits: (description length).
+ if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+
+ // (description length) bytes: Desc.
+ desc, err := readString(block.lr, int(x))
+ if err != nil {
+ return unexpected(err)
+ }
+ pic.Desc = desc
+
+ // 32 bits: Width.
+ if err = binary.Read(block.lr, binary.BigEndian, &pic.Width); err != nil {
+ return unexpected(err)
+ }
+
+ // 32 bits: Height.
+ if err = binary.Read(block.lr, binary.BigEndian, &pic.Height); err != nil {
+ return unexpected(err)
+ }
+
+ // 32 bits: Depth.
+ if err = binary.Read(block.lr, binary.BigEndian, &pic.Depth); err != nil {
+ return unexpected(err)
+ }
+
+ // 32 bits: NPalColors.
+ if err = binary.Read(block.lr, binary.BigEndian, &pic.NPalColors); err != nil {
+ return unexpected(err)
+ }
+
+ // 32 bits: (data length).
+ if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ if x == 0 {
+ return nil
+ }
+
+ // (data length) bytes: Data.
+ pic.Data = make([]byte, x)
+ _, err = io.ReadFull(block.lr, pic.Data)
+ return unexpected(err)
+}
diff --git a/meta/reader.go b/meta/reader.go
new file mode 100755
index 0000000..58f55b6
--- /dev/null
+++ b/meta/reader.go
@@ -0,0 +1,24 @@
+package meta
+
+import "io"
+
+// readString reads and returns exactly n bytes from the provided io.Reader.
+//
+// The error is io.EOF only if no bytes were read. If an io.EOF happens after
+// reading some but not all the bytes, ReadFull returns io.ErrUnexpectedEOF. On
+// return, n == len(buf) if and only if err == nil.
+func readString(r io.Reader, n int) (string, error) {
+ // readBuf is the local buffer used by readBytes.
+ var backingArray [4096]byte // hopefully allocated on stack.
+ readBuf := backingArray[:]
+ if n > len(readBuf) {
+ // The local buffer is initially 4096 bytes and will grow automatically if
+ // so required.
+ readBuf = make([]byte, n)
+ }
+ _, err := io.ReadFull(r, readBuf[:n])
+ if err != nil {
+ return "", err
+ }
+ return string(readBuf[:n]), nil
+}
diff --git a/meta/seektable.go b/meta/seektable.go
new file mode 100755
index 0000000..c0b96ce
--- /dev/null
+++ b/meta/seektable.go
@@ -0,0 +1,67 @@
+package meta
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+)
+
+// SeekTable contains one or more pre-calculated audio frame seek points.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_seektable
+type SeekTable struct {
+ // One or more seek points.
+ Points []SeekPoint
+}
+
+// parseSeekTable reads and parses the body of a SeekTable metadata block.
+func (block *Block) parseSeekTable() error {
+ // The number of seek points is derived from the header length, divided by
+ // the size of a SeekPoint; which is 18 bytes.
+ n := block.Length / 18
+ if n < 1 {
+ return errors.New("meta.Block.parseSeekTable: at least one seek point is required")
+ }
+ table := &SeekTable{Points: make([]SeekPoint, n)}
+ block.Body = table
+ var prev uint64
+ for i := range table.Points {
+ point := &table.Points[i]
+ err := binary.Read(block.lr, binary.BigEndian, point)
+ if err != nil {
+ return unexpected(err)
+ }
+ // Seek points within a table must be sorted in ascending order by sample
+ // number. Each seek point must have a unique sample number, except for
+ // placeholder points.
+ sampleNum := point.SampleNum
+ if i != 0 && sampleNum != PlaceholderPoint {
+ switch {
+ case sampleNum < prev:
+ return fmt.Errorf("meta.Block.parseSeekTable: invalid seek point order; sample number (%d) < prev (%d)", sampleNum, prev)
+ case sampleNum == prev:
+ return fmt.Errorf("meta.Block.parseSeekTable: duplicate seek point with sample number (%d)", sampleNum)
+ }
+ }
+ }
+ return nil
+}
+
+// A SeekPoint specifies the byte offset and initial sample number of a given
+// target frame.
+//
+// ref: https://www.xiph.org/flac/format.html#seekpoint
+type SeekPoint struct {
+ // Sample number of the first sample in the target frame, or
+ // 0xFFFFFFFFFFFFFFFF for a placeholder point.
+ SampleNum uint64
+ // Offset in bytes from the first byte of the first frame header to the first
+ // byte of the target frame's header.
+ Offset uint64
+ // Number of samples in the target frame.
+ NSamples uint16
+}
+
+// PlaceholderPoint represent the sample number used to specify placeholder seek
+// points.
+const PlaceholderPoint = 0xFFFFFFFFFFFFFFFF
diff --git a/meta/streaminfo.go b/meta/streaminfo.go
new file mode 100755
index 0000000..f72fbfc
--- /dev/null
+++ b/meta/streaminfo.go
@@ -0,0 +1,116 @@
+package meta
+
+import (
+ "crypto/md5"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/mewkiz/flac/internal/bits"
+)
+
+// StreamInfo contains the basic properties of a FLAC audio stream, such as its
+// sample rate and channel count. It is the only mandatory metadata block and
+// must be present as the first metadata block of a FLAC stream.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_streaminfo
+type StreamInfo struct {
+ // Minimum block size (in samples) used in the stream; between 16 and 65535
+ // samples.
+ BlockSizeMin uint16
+ // Maximum block size (in samples) used in the stream; between 16 and 65535
+ // samples.
+ BlockSizeMax uint16
+ // Minimum frame size in bytes; a 0 value implies unknown.
+ FrameSizeMin uint32
+ // Maximum frame size in bytes; a 0 value implies unknown.
+ FrameSizeMax uint32
+ // Sample rate in Hz; between 1 and 655350 Hz.
+ SampleRate uint32
+ // Number of channels; between 1 and 8 channels.
+ NChannels uint8
+ // Sample size in bits-per-sample; between 4 and 32 bits.
+ BitsPerSample uint8
+ // Total number of inter-channel samples in the stream. One second of 44.1
+ // KHz audio will have 44100 samples regardless of the number of channels. A
+ // 0 value implies unknown.
+ NSamples uint64
+ // MD5 checksum of the unencoded audio data.
+ MD5sum [md5.Size]uint8
+}
+
+// parseStreamInfo reads and parses the body of a StreamInfo metadata block.
+func (block *Block) parseStreamInfo() error {
+ // 16 bits: BlockSizeMin.
+ br := bits.NewReader(block.lr)
+ x, err := br.Read(16)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x < 16 {
+ return fmt.Errorf("meta.Block.parseStreamInfo: invalid minimum block size (%d); expected >= 16", x)
+ }
+ si := new(StreamInfo)
+ block.Body = si
+ si.BlockSizeMin = uint16(x)
+
+ // 16 bits: BlockSizeMax.
+ x, err = br.Read(16)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x < 16 {
+ return fmt.Errorf("meta.Block.parseStreamInfo: invalid maximum block size (%d); expected >= 16", x)
+ }
+ si.BlockSizeMax = uint16(x)
+
+ // 24 bits: FrameSizeMin.
+ x, err = br.Read(24)
+ if err != nil {
+ return unexpected(err)
+ }
+ si.FrameSizeMin = uint32(x)
+
+ // 24 bits: FrameSizeMax.
+ x, err = br.Read(24)
+ if err != nil {
+ return unexpected(err)
+ }
+ si.FrameSizeMax = uint32(x)
+
+ // 20 bits: SampleRate.
+ x, err = br.Read(20)
+ if err != nil {
+ return unexpected(err)
+ }
+ if x == 0 {
+ return errors.New("meta.Block.parseStreamInfo: invalid sample rate (0)")
+ }
+ si.SampleRate = uint32(x)
+
+ // 3 bits: NChannels.
+ x, err = br.Read(3)
+ if err != nil {
+ return unexpected(err)
+ }
+ // x contains: (number of channels) - 1
+ si.NChannels = uint8(x + 1)
+
+ // 5 bits: BitsPerSample.
+ x, err = br.Read(5)
+ if err != nil {
+ return unexpected(err)
+ }
+ // x contains: (bits-per-sample) - 1
+ si.BitsPerSample = uint8(x + 1)
+
+ // 36 bits: NSamples.
+ si.NSamples, err = br.Read(36)
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // 16 bytes: MD5sum.
+ _, err = io.ReadFull(block.lr, si.MD5sum[:])
+ return unexpected(err)
+}
diff --git a/meta/testdata/README.md b/meta/testdata/README.md
new file mode 100755
index 0000000..f2ec6b0
--- /dev/null
+++ b/meta/testdata/README.md
@@ -0,0 +1,35 @@
+# Testcase Licences
+
+## BSD License
+
+The following testcase sounds have been copied from the [reference implementation] library, which is released under a [BSD license].
+
+* input-SCPAP.flac
+* input-SCVA.flac
+* input-SCVAUP.flac
+* input-SCVPAP.flac
+* input-SVAUP.flac
+* input-VA.flac
+* `missing-value.flac`, created using the following command.
+
+```shell
+sed 's/title=/title /' input-SCVA.flac > missing-value.flac
+```
+
+[reference implementation]: https://git.xiph.org/?p=flac.git
+[BSD license]: https://git.xiph.org/?p=flac.git;a=blob_plain;f=COPYING.Xiph
+
+## Public domain
+
+The following testcase images and sounds have been released into the [public domain].
+
+* [silence.jpg](http://www.pdpics.com/photo/2546-silence-word-magnified/)
+* `silence.flac`, created using the following commands.
+
+```shell
+ffmpeg -f lavfi -i "aevalsrc=0|0:d=3" silence.wav
+flac silence.wav
+metaflac --import-picture=silence.jpg silence.flac
+```
+
+[public domain]: https://creativecommons.org/publicdomain/zero/1.0/
diff --git a/meta/testdata/silence.jpg b/meta/testdata/silence.jpg
new file mode 100755
index 0000000..6236e6d
Binary files /dev/null and b/meta/testdata/silence.jpg differ
diff --git a/meta/vorbiscomment.go b/meta/vorbiscomment.go
new file mode 100755
index 0000000..313f857
--- /dev/null
+++ b/meta/vorbiscomment.go
@@ -0,0 +1,69 @@
+package meta
+
+import (
+ "encoding/binary"
+ "fmt"
+ "strings"
+)
+
+// VorbisComment contains a list of name-value pairs.
+//
+// ref: https://www.xiph.org/flac/format.html#metadata_block_vorbis_comment
+type VorbisComment struct {
+ // Vendor name.
+ Vendor string
+ // A list of tags, each represented by a name-value pair.
+ Tags [][2]string
+}
+
+// parseVorbisComment reads and parses the body of a VorbisComment metadata
+// block.
+func (block *Block) parseVorbisComment() (err error) {
+ // 32 bits: vendor length.
+ var x uint32
+ if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil {
+ return unexpected(err)
+ }
+
+ // (vendor length) bits: Vendor.
+ vendor, err := readString(block.lr, int(x))
+ if err != nil {
+ return unexpected(err)
+ }
+ comment := new(VorbisComment)
+ block.Body = comment
+ comment.Vendor = vendor
+
+ // Parse tags.
+ // 32 bits: number of tags.
+ if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil {
+ return unexpected(err)
+ }
+ if x < 1 {
+ return nil
+ }
+ comment.Tags = make([][2]string, x)
+ for i := range comment.Tags {
+ // 32 bits: vector length
+ if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil {
+ return unexpected(err)
+ }
+
+ // (vector length): vector.
+ vector, err := readString(block.lr, int(x))
+ if err != nil {
+ return unexpected(err)
+ }
+
+ // Parse tag, which has the following format:
+ // NAME=VALUE
+ pos := strings.Index(vector, "=")
+ if pos == -1 {
+ return fmt.Errorf("meta.Block.parseVorbisComment: unable to locate '=' in vector %q", vector)
+ }
+ comment.Tags[i][0] = vector[:pos]
+ comment.Tags[i][1] = vector[pos+1:]
+ }
+
+ return nil
+}
diff --git a/testdata/README.md b/testdata/README.md
new file mode 100755
index 0000000..ac6d321
--- /dev/null
+++ b/testdata/README.md
@@ -0,0 +1,22 @@
+## Public domain
+
+The following testcase sounds have been released into the [public domain].
+
+* [19875.flac](http://freesound.org/people/yawfle/sounds/19875/)
+* [44127.flac](http://freesound.org/people/dland/sounds/44127/)
+* [59996.flac](http://freesound.org/people/qubodup/sounds/59996/)
+* [80574.flac](http://freesound.org/people/EsbenSloth/sounds/80574/)
+* [172960.flac](http://freesound.org/people/qubodup/sounds/172960/)
+* [189983.flac](http://freesound.org/people/raygrote/sounds/189983/)
+* [191885.flac](http://freesound.org/people/Hedmarking/sounds/191885/)
+* [212768.flac](http://freesound.org/people/qubodup/sounds/212768/)
+* [220014.flac](http://freesound.org/people/djani00/sounds/220014/)
+* [243749.flac](http://freesound.org/people/unfa/sounds/243749/)
+* [256529.flac](http://freesound.org/people/tymorafarr/sounds/256529/)
+* [257344.flac](http://freesound.org/people/arseniiv/sounds/257344/)
+
+[public domain]: https://creativecommons.org/publicdomain/zero/1.0/
+
+The following flac files are CC BY 4.0:
+
+* [8297-275156-0011.flac](http://www.openslr.org/12/) - a single file from the LibriSpeech ASR corpus, by Vassil Panyotov and DanielPovey.