diff --git a/.devops/cublas.Dockerfile b/.devops/cublas.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..ca87fdda086a23c3aa05d7f3bb4d86366090713f --- /dev/null +++ b/.devops/cublas.Dockerfile @@ -0,0 +1,28 @@ +ARG UBUNTU_VERSION=22.04 + +# This needs to generally match the container host's environment. +ARG CUDA_VERSION=11.7.1 + +# Target the CUDA build image +ARG BASE_CUDA_DEV_CONTAINER=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} + +FROM ${BASE_CUDA_DEV_CONTAINER} as build + +# Unless otherwise specified, we make a fat build. +ARG CUDA_DOCKER_ARCH=all + +RUN apt-get update && \ + apt-get install -y build-essential git cmake + +WORKDIR /app + +COPY . . + +# Set nvcc architecture +ENV CUDA_DOCKER_ARCH=${CUDA_DOCKER_ARCH} +# Enable cuBLAS +ENV GGML_CUDA=1 + +RUN make + +ENTRYPOINT ["/app/main"] diff --git a/.devops/main-cuda.Dockerfile b/.devops/main-cuda.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..674b64c23df2a67b871698b5a4bd5007c00d9f71 --- /dev/null +++ b/.devops/main-cuda.Dockerfile @@ -0,0 +1,40 @@ +ARG UBUNTU_VERSION=22.04 +# This needs to generally match the container host's environment. +ARG CUDA_VERSION=12.3.1 +# Target the CUDA build image +ARG BASE_CUDA_DEV_CONTAINER=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} +# Target the CUDA runtime image +ARG BASE_CUDA_RUN_CONTAINER=nvidia/cuda:${CUDA_VERSION}-runtime-ubuntu${UBUNTU_VERSION} + +FROM ${BASE_CUDA_DEV_CONTAINER} AS build +WORKDIR /app + +# Unless otherwise specified, we make a fat build. +ARG CUDA_DOCKER_ARCH=all +# Set nvcc architecture +ENV CUDA_DOCKER_ARCH=${CUDA_DOCKER_ARCH} +# Enable cuBLAS +ENV GGML_CUDA=1 + +RUN apt-get update && \ + apt-get install -y build-essential \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* + +# Ref: https://stackoverflow.com/a/53464012 +ENV CUDA_MAIN_VERSION=12.3 +ENV LD_LIBRARY_PATH /usr/local/cuda-${CUDA_MAIN_VERSION}/compat:$LD_LIBRARY_PATH + +COPY .. . +RUN make + +FROM ${BASE_CUDA_RUN_CONTAINER} AS runtime +ENV CUDA_MAIN_VERSION=12.3 +ENV LD_LIBRARY_PATH /usr/local/cuda-${CUDA_MAIN_VERSION}/compat:$LD_LIBRARY_PATH +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y curl ffmpeg \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* + +COPY --from=build /app /app +ENTRYPOINT [ "bash", "-c" ] diff --git a/.devops/main.Dockerfile b/.devops/main.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..f923a9063d8328db672e4ab6ec5275becc026b61 --- /dev/null +++ b/.devops/main.Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:22.04 AS build +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y build-essential \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* + +COPY .. . +RUN make + +FROM ubuntu:22.04 AS runtime +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y curl ffmpeg \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* + +COPY --from=build /app /app +ENTRYPOINT [ "bash", "-c" ] diff --git a/.github/workflows/bindings-go.yml b/.github/workflows/bindings-go.yml new file mode 100644 index 0000000000000000000000000000000000000000..13f1950a5ba59b132d1ddbf29689325a6fb968eb --- /dev/null +++ b/.github/workflows/bindings-go.yml @@ -0,0 +1,22 @@ +name: Bindings Tests (Go) +on: + push: + paths: + - bindings/go/** + - whisper.h + pull_request: + paths: + - bindings/go/** + - whisper.h + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: '^1.19' + - uses: actions/checkout@v1 + - run: | + cd bindings/go + make test diff --git a/.github/workflows/bindings-ruby.yml.disabled b/.github/workflows/bindings-ruby.yml.disabled new file mode 100644 index 0000000000000000000000000000000000000000..1f36b79c3a7bf9e7cde8666913c1fb07b27e578a --- /dev/null +++ b/.github/workflows/bindings-ruby.yml.disabled @@ -0,0 +1,23 @@ +# TODO: fix this workflow file, disabled for now +name: Bindings Tests (Ruby) +on: + push: + paths: + - bindings/ruby/** + - whisper.h + pull_request: + paths: + - bindings/ruby/** + - whisper.h + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + steps: + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0' + - uses: actions/checkout@v1 + - run: | + cd bindings/ruby/ext + ruby extconf.rb && make diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000000000000000000000000000000..d4077ad004c07d0b4cdda5283e036460bc2a5997 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,669 @@ +name: CI +on: [push, pull_request] + +env: + ubuntu_image: "ubuntu:22.04" + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential libsdl2-dev + make + make stream' + + macOS-latest: + runs-on: macOS-latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Dependencies + run: | + brew update + brew install sdl2 + + - name: Build + run: | + make + make stream + + freeBSD-latest: + runs-on: macos-12 + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Build + uses: cross-platform-actions/action@v0.24.0 + with: + operating_system: freebsd + version: '13.3' + run: | + sudo pkg update + sudo pkg install -y gmake sdl2 + gmake + gmake stream + + ubuntu-latest-gcc: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + build: [Debug, Release] + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential cmake libsdl2-dev + cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} + make + ctest -L gh --output-on-failure' + + ubuntu-latest-clang: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + build: [Debug, Release] + #arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + # TODO: arm/v7 disabled due to clang bug + # https://github.com/ggerganov/whisper.cpp/actions/runs/9657764109/job/26637633042?pr=2256#step:4:1990 + arch: [linux/amd64, linux/arm64, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y clang build-essential cmake libsdl2-dev + cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang + make + ctest -L gh --output-on-failure' + + ubuntu-latest-gcc-sanitized: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + sanitizer: [ADDRESS, THREAD, UNDEFINED] + arch: [linux/amd64] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential cmake + cmake . -DCMAKE_BUILD_TYPE=Debug -DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON + make + ctest -L gh --output-on-failure' + + ubuntu-22-cmake-sycl: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + dwhisper_sycl: [ON] + dcmake_c_compiler: [icx] + dcmake_cxx_compiler: [icpx] + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + continue-on-error: true + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: add oneAPI to apt + shell: bash + run: | + cd /tmp + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" + + - name: install oneAPI dpcpp compiler + shell: bash + run: | + sudo apt update + sudo apt install intel-oneapi-compiler-dpcpp-cpp + + - name: install oneAPI MKL library + shell: bash + run: | + sudo apt install intel-oneapi-mkl-devel + + - name: Clone + id: checkout + uses: actions/checkout@v4 + + - name: Build + id: cmake_build + run: | + source /opt/intel/oneapi/setvars.sh + mkdir build + cd build + cmake -DGGML_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx .. + cmake --build . --config Release -j $(nproc) + + ubuntu-22-cmake-sycl-fp16: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + dwhisper_sycl: [ON] + dcmake_c_compiler: [icx] + dcmake_cxx_compiler: [icpx] + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + continue-on-error: true + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: add oneAPI to apt + shell: bash + run: | + cd /tmp + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" + + - name: install oneAPI dpcpp compiler + shell: bash + run: | + sudo apt update + sudo apt install intel-oneapi-compiler-dpcpp-cpp + + - name: install oneAPI MKL library + shell: bash + run: | + sudo apt install intel-oneapi-mkl-devel + + - name: Clone + id: checkout + uses: actions/checkout@v4 + + - name: Build + id: cmake_build + run: | + source /opt/intel/oneapi/setvars.sh + mkdir build + cd build + cmake -DGGML_SYCL_F16=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx .. + cmake --build . --config Release -j $(nproc) + + windows-msys2: + runs-on: windows-latest + + strategy: + fail-fast: false + matrix: + include: + - { sys: UCRT64, env: ucrt-x86_64, build: Release } + - { sys: CLANG64, env: clang-x86_64, build: Release } + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Setup ${{ matrix.sys }} + uses: msys2/setup-msys2@v2 + with: + update: true + msystem: ${{matrix.sys}} + install: >- + base-devel + mingw-w64-${{matrix.env}}-toolchain + mingw-w64-${{matrix.env}}-cmake + mingw-w64-${{matrix.env}}-SDL2 + mingw-w64-${{matrix.env}}-openblas + + - name: Build using make + shell: msys2 {0} + run: | + make -j $(nproc) + + - name: Clean after building using make + shell: msys2 {0} + run: | + make clean + + - name: Build using make w/ OpenBLAS + shell: msys2 {0} + run: | + make GGML_OPENBLAS=1 -j $(nproc) + + - name: Build using CMake + shell: msys2 {0} + run: | + cmake -B build + cmake --build build --config ${{ matrix.build }} -j $(nproc) + + - name: Clean after building using CMake + shell: msys2 {0} + run: | + rm -rf build + + - name: Build using CMake w/ OpenBLAS + shell: msys2 {0} + run: | + cmake -B build -DGGML_OPENBLAS=ON + cmake --build build --config ${{ matrix.build }} -j $(nproc) + + windows: + runs-on: windows-latest + + strategy: + matrix: + build: [Release] + arch: [Win32, x64] + sdl2: [ON] + include: + - arch: Win32 + s2arc: x86 + jnaPath: win32-x86 + - arch: x64 + s2arc: x64 + jnaPath: win32-x86-64 + - sdl2: ON + s2ver: 2.28.5 + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DWHISPER_SDL2=${{ matrix.sdl2 }} + + - name: Build + run: | + cd ./build + msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload dll + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.jnaPath }}_whisper.dll + path: build/bin/${{ matrix.build }}/whisper.dll + + - name: Upload binaries + if: matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v4 + with: + name: whisper-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + windows-blas: + runs-on: windows-latest + + strategy: + matrix: + build: [Release] + arch: [Win32, x64] + blas: [ON] + sdl2: [ON] + include: + - arch: Win32 + obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x86.zip + s2arc: x86 + - arch: x64 + obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x64.zip + s2arc: x64 + - sdl2: ON + s2ver: 2.28.5 + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Fetch OpenBLAS + if: matrix.blas == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO blas.zip ${{ matrix.obzip }} + 7z x blas.zip -oblas -y + copy blas/include/cblas.h . + copy blas/include/openblas_config.h . + echo "OPENBLAS_PATH=$env:GITHUB_WORKSPACE/blas" >> $env:GITHUB_ENV + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DGGML_OPENBLAS=${{ matrix.blas }} + -DCMAKE_LIBRARY_PATH="$env:OPENBLAS_PATH/lib" + -DWHISPER_SDL2=${{ matrix.sdl2 }} + + - name: Build + run: | + cd ./build + msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} + + - name: Copy libopenblas.dll + if: matrix.blas == 'ON' + run: copy "$env:OPENBLAS_PATH/bin/libopenblas.dll" build/bin/${{ matrix.build }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload binaries + if: matrix.blas == 'ON' && matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v4 + with: + name: whisper-blas-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + windows-cublas: + runs-on: windows-2019 + + strategy: + matrix: + build: [Release] + arch: [x64] + cublas: [ON] + sdl2: [ON] + cuda-toolkit: [12.2.0, 11.8.0] + include: + - arch: x64 + s2arc: x64 + - sdl2: ON + s2ver: 2.28.5 + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Install CUDA Toolkit + id: cuda-toolkit + uses: Jimver/cuda-toolkit@v0.2.15 + with: + cuda: '${{ matrix.cuda-toolkit }}' + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DGGML_CUDA=${{ matrix.cublas }} + -DWHISPER_SDL2=${{ matrix.sdl2 }} + + - name: Build ${{ matrix.cuda-toolkit }} + run: | + cd ./build + cmake --build . --config ${{ matrix.build }} + + - name: Copy CUDA DLLs + run: > + Copy-Item -PassThru + -Path "${{ steps.cuda-toolkit.outputs.CUDA_PATH }}/bin/*.dll" + -Include cudart64_*,cublas64_*,cublasLt64_* + -Destination build/bin/${{ matrix.build }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload binaries + if: matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v4 + with: + name: whisper-cublas-${{ matrix.cuda-toolkit }}-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + emscripten: + runs-on: ubuntu-latest + + strategy: + matrix: + build: [Release] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Setup emsdk + uses: mymindstorm/setup-emsdk@v14 + + - name: Verify + run: emcc -v + + - name: Build + run: | + emcmake cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }} + make + + ios: + runs-on: macos-latest + + strategy: + matrix: + build: [Release] + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Configure + run: | + cp models/for-tests-ggml-base.en.bin models/ggml-base.en.bin + mkdir models/ggml-base.en-encoder.mlmodelc + + - name: Build objc example + run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphonesimulator build + + - name: Build swiftui example + run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphonesimulator build + + android: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v4 + with: + path: whisper + + - name: Clone + uses: actions/checkout@v4 + with: + repository: ggerganov/ggml + path: ggml + + - name: Install Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 21 + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Build + run: | + cd whisper/examples/whisper.android + ./gradlew assembleRelease --no-daemon + + - name: Build with external ggml + run: | + export PATH_TO_GGML=$PWD/ggml + cd whisper/examples/whisper.android + ./gradlew assembleRelease --no-daemon -PGGML_HOME=$PATH_TO_GGML + + android_java: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + cache: gradle + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + with: + cmdline-tools-version: 9.0 + + - name: Build + run: | + cd examples/whisper.android.java + chmod +x ./gradlew + ./gradlew assembleRelease + +# TODO: disabled because of following fail: https://github.com/ggerganov/whisper.cpp/actions/runs/9686220096/job/26735899598 +# java: +# needs: [ 'windows' ] +# runs-on: windows-latest +# steps: +# - uses: actions/checkout@v4 +# +# - name: Install Java +# uses: actions/setup-java@v4 +# with: +# distribution: zulu +# java-version: 20 +# +# - name: Download Windows lib +# uses: actions/download-artifact@v4 +# with: +# name: win32-x86-64_whisper.dll +# path: bindings/java/build/generated/resources/main/win32-x86-64 +# +# - name: Build +# run: | +# models\download-ggml-model.cmd tiny.en +# cd bindings/java +# chmod +x ./gradlew +# ./gradlew build +# +# - name: Upload jar +# uses: actions/upload-artifact@v4 +# with: +# name: whispercpp.jar +# path: bindings/java/build/libs/whispercpp-*.jar +# +# - name: Publish package +# if: ${{ github.ref == 'refs/heads/master' }} +# uses: gradle/gradle-build-action@v2.4.2 +# with: +# arguments: publish +# build-root-directory: bindings/java +# env: +# MAVEN_USERNAME: ${{ secrets.JIRA_USER }} +# MAVEN_PASSWORD: ${{ secrets.JIRA_PASS }} +# PGP_SECRET: ${{ secrets.GPG_PRIVATE_KEY }} +# PGP_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + + quantize: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Test quantize + run: | + ./models/download-ggml-model.sh tiny.en + make quantize + ./quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..c5a80f269ef791aff5d03cd243a2b24e89174ec1 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,57 @@ +name: Publish Docker image + +on: + pull_request: + push: + branches: + - master + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + if: github.event.pull_request.draft == false + + runs-on: ubuntu-latest + env: + COMMIT_SHA: ${{ github.sha }} + strategy: + matrix: + config: + - { tag: "main", dockerfile: ".devops/main.Dockerfile", platform: "linux/amd64,linux/arm64" } + - { tag: "main-cuda", dockerfile: ".devops/main-cuda.Dockerfile", platform: "linux/amd64" } + + steps: + - name: Check out the repo + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image (versioned) + if: github.event_name == 'push' + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: ${{ matrix.config.platforms }} + tags: "ghcr.io/${{ github.repository }}:${{ matrix.config.tag }}-${{ env.COMMIT_SHA }}" + file: ${{ matrix.config.dockerfile }} + + - name: Build and push Docker image (tagged) + uses: docker/build-push-action@v4 + with: + context: . + push: ${{ github.event_name == 'push' }} + platforms: ${{ matrix.config.platforms }} + tags: "ghcr.io/${{ github.repository }}:${{ matrix.config.tag }}" + file: ${{ matrix.config.dockerfile }} diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 0000000000000000000000000000000000000000..808dd18c0b70705bd3bc749bb222ad0ca3307173 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,48 @@ +name: Examples Tests +on: + push: + paths: + - examples/addon.node/** + - whisper.h + pull_request: + paths: + - examples/addon.node/** + - whisper.h + +jobs: + addon_node-ubuntu-latest: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 16.x, 18.x ] + steps: + - name: Clone + uses: actions/checkout@v1 + + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential + sudo apt-get install cmake + sudo apt-get install libsdl2-dev + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Install package.json dependencies + working-directory: ./examples/addon.node + run: npm install + + - name: Compile addon.node + run: npx cmake-js compile -T addon.node -B Release + + - name: Download test model + run: | + bash ./models/download-ggml-model.sh base.en + - name: Test + run: | + cd examples/addon.node + npm run test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..44648fa7ba010b3392e9f7b3c4e903c7ab1fb0ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +*.o +*.a +.cache/ +.coreml/ +.test/ +.vs/ +.vscode/ +.DS_Store +.vimspector.json +/CMakeSettings.json + +build/ +build-*/ + +# SPM +.build/ +.swiftpm +*.metallib + +/main +/stream +/command +/talk +/talk-llama +/bench +/quantize +/server +/lsp + +arm_neon.h +sync.sh +libwhisper.a +libwhisper.so +compile_commands.json + +examples/arm_neon.h +examples/whisper.objc/whisper.objc.xcodeproj/xcshareddata +examples/whisper.objc/whisper.objc.xcodeproj/xcuserdata/ +examples/whisper.objc/whisper.objc.xcodeproj/project.xcworkspace/xcuserdata + +extra/bench-gg.txt + +models/*.mlmodel +models/*.mlmodelc +models/*.mlpackage +bindings/java/.gradle/ +bindings/java/.idea/ +.idea/ + +benchmark_results.csv +cmake-build-debug/ +.cxx/ +.gradle/ +local.properties diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..33e6c9649c728164414ab439734d48d4c496570d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,301 @@ +# date: Tue Apr 9 20:27:03 EEST 2024 +# this file is auto-generated by scripts/gen-authors.sh + +0/0 +0cc4m +0xsourcecode <134374803+0xsourcecode@users.noreply.github.com> +AT +Aarni Koskela +Aaron Pham <29749331+aarnphm@users.noreply.github.com> +Aaron Taylor +Abhilash Majumder <30946547+abhilash1910@users.noreply.github.com> +Abitofevrything <54505189+abitofevrything@users.noreply.github.com> +AfryMask +Ahmad Bilal +AidanBeltonS <87009434+AidanBeltonS@users.noreply.github.com> +Akash Mahajan +Akash Mahajan +Al Hoang <3811822-hoanga@users.noreply.gitlab.com> +Alan +Aleksander Andrzejewski <18704749+aleksanderandrzejewski@users.noreply.github.com> +Alex Azarov +Alex Bacart <13940752+alex-bacart@users.noreply.github.com> +Alex Evgrashin +Alexandr Graschenkov +Alexandru Mariuti +Alexey Kharlamov +Alfredo Montesinos +Ali Alameh +Ananta Bastola +Andreu Huguet +Andrew Huynh +Andrew S +Andy Maloney +Anton Kostin +Artyom Mezin +Asad Memon +Ashraful Islam +AsukaMinato +AustinMroz +Avik Sengupta +Bader-eddine Ouaich <49657842+baderouaich@users.noreply.github.com> +Baffin Lee +Ben Nortier +Benjamin Heiniger +Bo-Yi Wu +Boris Bliznioukov +Borislav Stanimirov +Brad Murray <59848399+bradmurray-dt@users.noreply.github.com> +Brian Murray +CRD716 +Canis Lupus +Carolinabanana <140120812+Carolinabanana@users.noreply.github.com> +ChangSeok Oh +Chaoqun <27287694+OpenWaygate@users.noreply.github.com> +Chia-Hsiang Cheng <88014292+garychia@users.noreply.github.com> +Chidi Williams +Christian <12550267+iceychris@users.noreply.github.com> +Clifford Heath +Colin +DGdev91 +Damian Czaja +Daniel Bevenius +David +David Thorpe +Davidson Francis +Dener Stassun +Didzis Gosko +Digipom +Dimo +Dody Suria Wijaya +Dr. Tom Murphy VII Ph.D <499244+tom7@users.noreply.github.com> +Duncan McConnell +Egor Egorov +Elkana Bardugo +Emmanuel Schmidbauer +Engininja2 <139037756+Engininja2@users.noreply.github.com> +Eric Swanson +Eric Tendian +Erik Scholz +Evan Jones +Evan Martin +Eve <139727413+netrunnereve@users.noreply.github.com> +Evgeny Kuznetsov +F1L1P <78918286+F1L1Pv2@users.noreply.github.com> +Fangjun Kuang +Felix +Finn Voorhees +FlippFuzz <41221030+FlippFuzz@users.noreply.github.com> +Gang Chen +Gavin Cai +George Hindle +Georgi Gerganov +GitAritron <103900385+GitAritron@users.noreply.github.com> +GiviMAD +Gleicon Moraes +Gregor Jasny +Guillaume Wenzek +HY. Kelvin Lee <34256578+hykelvinlee42@users.noreply.github.com> +Halalaluyafail3 <55773281+Halalaluyafail3@users.noreply.github.com> +Hang +Herman Semenov +Hrishikesh Barman +Ian Bicking +Ian Bull +Ikko Ashimine +InconsolableCellist <23345188+InconsolableCellist@users.noreply.github.com> +Ismatulla Mansurov <47342870+sapoepsilon@users.noreply.github.com> +Ivan Gorin +JJ <103335846+computerscienceiscool@users.noreply.github.com> +Jack Mousseau +JacobLinCool +Jakub Ráček +Jared Van Bortel +Jay Binks +Jhen-Jie Hong +Jhen-Jie Hong +JidongZhang-THU <1119708529@qq.com> +Jo Liss +Johan +Johannes Gäßler +John Balis +Jonathan Soo +Jonno <1160532+razodactyl@users.noreply.github.com> +Joonas Pihlajamaa +Jose <34888496+Jerry-Master@users.noreply.github.com> +Josh Bleecher Snyder +Judd +Jumper775 <78500318+jumpers775@users.noreply.github.com> +Justine Tunney +KP Kaiser +Kamilake +Kartik Saranathan <278928+Kartiku@users.noreply.github.com> +Kasumi <90275229+kasumi-1@users.noreply.github.com> +Kawrakow <48489457+ikawrakow@users.noreply.github.com> +Kevin Brothaler +Konstantin Zhuravlyov +Kreijstal +Kylin <56434533+KyL0N@users.noreply.github.com> +LBlue <153975653+lbluep@users.noreply.github.com> +Larry Battle +Laytan Laats +Leo Moll +Lexevolution <31176843+Lexevolution@users.noreply.github.com> +LittleLoli <26589867+WhichWho@users.noreply.github.com> +Lucas Zanek <57494138+LucasZNK@users.noreply.github.com> +Luis Herrera +Lukas Rist +M. A. Ali <73258591+MightyStud@users.noreply.github.com> +M. Eren Akbiyik +Maciek +Marcin Mielniczuk +Martin Warnaar +Matheus de Sousa <23645013+keyehzy@users.noreply.github.com> +Mathijs de Bruin +Matija Pevec +Maximiliano Levi <8160966+maxilevi@users.noreply.github.com> +Meng, Hengyu +Michael Podvitskiy +Michael Rienstra +Mikhail Grigorev +Mohammadreza Hendiani +Mohit Agarwal +Murilo Santana +Neil Chudleigh +Neo Zhang Jianyu +Neuman Vong +Nicholas Albion +Niels Mayer +Okabintaro <103938900+Okabintaro@users.noreply.github.com> +Oleg Sidorov +Oleg Sidorov +Ondrej Kokes +Ouadie EL FAROUKI +Paul Tsochantaris +Philipp Zabel +Philippe Normand +Przemysław Pawełczyk +Qianhe Chen <54462604+chenqianhe@users.noreply.github.com> +Radosław Gryta +Reinforce-II +Reinis Muiznieks +RelatedTitle +RhinoDevel +Rich Jones +Robin +Roddur Dasgupta +Roland Rabien +Rotem Dan +Ryan Hitchman +Ryan Metcalfe <107415876+RyanMetcalfeInt8@users.noreply.github.com> +RyanChang +Sam <49637763+Onlyartist9@users.noreply.github.com> +Sam Pullara +Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com> +Sergio López +Siddharth Ramakrishnan +Simon Moisselin +Sindre Sorhus +Slava Primenko +Syahmi Azhar +Syed Jafri +Sơn Phan Trung +Taisei Mima +Takeshi Inoue +Tamotsu Takahashi +Taras Glek +Tauseef Mohiuddin <35351464+tauseefmohammed2@users.noreply.github.com> +Thijs Raymakers +Thomas Fitzsimmons +Tiago Fassoni +Tienshiao Ma +Timothy Cronin <40186632+4imothy@users.noreply.github.com> +Tobrun +Todd +Tong Li <31761981+litongjava@users.noreply.github.com> +Topping1 <78745143+Topping1@users.noreply.github.com> +Travis Cline +UEXTM.com <84163508+uextm@users.noreply.github.com> +Vadim Peretokin +Valentin Gosu <1454649+valenting@users.noreply.github.com> +Vulcan <93451215+trholding@users.noreply.github.com> +WhiteOlivierus <36532695+WhiteOlivierus@users.noreply.github.com> +Xiang (Kevin) Li +Xiao-Yong Jin +XiaotaoChen +Yajing Tang +Yang Shen +Yunès +ZaBlazzingZephyrus <119159668+blazingzephyr@users.noreply.github.com> +Zigfrid Zvezdin +Zollner <24618122+Zolliner@users.noreply.github.com> +ai-at-home <149282006+ai-at-home@users.noreply.github.com> +alonfaraj +andypayne +ardfork <134447697+ardfork@users.noreply.github.com> +automaticcat +be-next +bert hubert +bmwl +bobqianic <129547291+bobqianic@users.noreply.github.com> +bocytko +boolemancer <48014766+boolemancer@users.noreply.github.com> +boolemancer +bradmit <151883577+bradmit@users.noreply.github.com> +brunofaustino +bssrdf +byte-6174 <88070277+byte-6174@users.noreply.github.com> +cdosoftei +clach04 +compilade <113953597+compilade@users.noreply.github.com> +conradg +ddpasa <112642920+ddpasa@users.noreply.github.com> +denersc +dscripka +duthils +ecneladis +faker +fitzsim +fraxy-v <65565042+fraxy-v@users.noreply.github.com> +genevera (she/her) +geniusnut +greeshmay +hydai +iamthad +james wolf +joecryptotoo <80373433+joecryptotoo@users.noreply.github.com> +jorismertz <35079666+jorismertz@users.noreply.github.com> +junkfood <69683722+JunkFood02@users.noreply.github.com> +jwijffels +kamranjon +katsu560 +kennethge <57784063+kenneth-ge@users.noreply.github.com> +keyehzy +leejet +litong <31761981+litongjava@users.noreply.github.com> +lnyan +m.bell +mkiol +novag <7754358+novag@users.noreply.github.com> +pajowu +polarmoon <90010972+polarmoon@users.noreply.github.com> +rlapray +sandrohanea <40202887+sandrohanea@users.noreply.github.com> +semiformal-net <84111142+semiformal-net@users.noreply.github.com> +shibukazu <61775791+shibukazu@users.noreply.github.com> +shikokuchuo <53399081+shikokuchuo@users.noreply.github.com> +slaren +slashlib +snadampal <87143774+snadampal@users.noreply.github.com> +st-gr <38470677+st-gr@users.noreply.github.com> +texmex76 <40733439+texmex76@users.noreply.github.com> +thefinaldegree +trixirt +ulatekh +undef +venkr +vicalloy +xdrudis +zhouwg <6889919+zhouwg@users.noreply.github.com> +布客飞龙 <562826179@qq.com> +Артём Земляк diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb17def7d40c1d084a9844d3ac872dcdf9d9ef5f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,185 @@ +cmake_minimum_required(VERSION 3.5) # for add_link_options and implicit target directories. +project("whisper.cpp" C CXX) +project("whisper.cpp" VERSION 1.6.2) +include(CheckIncludeFileCXX) + +set(SOVERSION 1) + +#set(CMAKE_WARN_DEPRECATED YES) +set(CMAKE_WARN_UNUSED_CLI YES) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if (NOT XCODE AND NOT MSVC AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +# Add path to modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(WHISPER_STANDALONE ON) + + include(git-vars) + + # configure project version + configure_file(${CMAKE_SOURCE_DIR}/bindings/javascript/package-tmpl.json ${CMAKE_SOURCE_DIR}/bindings/javascript/package.json @ONLY) +else() + set(WHISPER_STANDALONE OFF) +endif() + +if (EMSCRIPTEN) + set(BUILD_SHARED_LIBS_DEFAULT OFF) + + option(WHISPER_WASM_SINGLE_FILE "whisper: embed WASM inside the generated whisper.js" ON) + + # TODO: without these, we get the following error: + # wasm-ld: error: --shared-memory is disallowed by whisper.cpp.o because it was not compiled with 'atomics' or 'bulk-memory' features. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -s TOTAL_STACK=5242880") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -s TOTAL_STACK=5242880") +else() + if (MINGW) + set(BUILD_SHARED_LIBS_DEFAULT OFF) + else() + set(BUILD_SHARED_LIBS_DEFAULT ON) + endif() +endif() + +option(BUILD_SHARED_LIBS "build shared libraries" ${BUILD_SHARED_LIBS_DEFAULT}) + +# +# option list +# + +# general +option(WHISPER_CCACHE "whisper: use ccache if available" ON) + +# debug +option(WHISPER_ALL_WARNINGS "whisper: enable all compiler warnings" ON) +option(WHISPER_ALL_WARNINGS_3RD_PARTY "whisper: enable all compiler warnings in 3rd party libs" OFF) + +# build +option(WHISPER_FATAL_WARNINGS "whisper: enable -Werror flag" OFF) + +# sanitizers +option(WHISPER_SANITIZE_THREAD "whisper: enable thread sanitizer" OFF) +option(WHISPER_SANITIZE_ADDRESS "whisper: enable address sanitizer" OFF) +option(WHISPER_SANITIZE_UNDEFINED "whisper: enable undefined sanitizer" OFF) + +# extra artifacts +option(WHISPER_BUILD_TESTS "whisper: build tests" ${WHISPER_STANDALONE}) +option(WHISPER_BUILD_EXAMPLES "whisper: build examples" ${WHISPER_STANDALONE}) +option(WHISPER_BUILD_SERVER "whisper: build server example" ${WHISPER_STANDALONE}) + +# 3rd party libs +option(WHISPER_CURL "whisper: use libcurl to download model from an URL" OFF) +option(WHISPER_SDL2 "whisper: support for libSDL2" OFF) + +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + option(WHISPER_FFMPEG "whisper: support building and linking with ffmpeg libs (avcodec, swresample, ...)" OFF) +endif() + +option(WHISPER_COREML "whisper: enable Core ML framework" OFF) +option(WHISPER_COREML_ALLOW_FALLBACK "whisper: allow non-CoreML fallback" OFF) +option(WHISPER_OPENVINO "whisper: support for OpenVINO" OFF) + +# Required for relocatable CMake package +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-info.cmake) + +# override ggml options +set(GGML_CCACHE ${WHISPER_CCACHE}) +set(GGML_SANITIZE_THREAD ${WHISPER_SANITIZE_THREAD}) +set(GGML_SANITIZE_ADDRESS ${WHISPER_SANITIZE_ADDRESS}) +set(GGML_SANITIZE_UNDEFINED ${WHISPER_SANITIZE_UNDEFINED}) +set(GGML_ALL_WARNINGS ${WHISPER_ALL_WARNINGS}) +set(GGML_FATAL_WARNINGS ${WHISPER_FATAL_WARNINGS}) + +# transition helpers +function (whisper_option_depr TYPE OLD NEW) + if (${OLD}) + message(${TYPE} "${OLD} is deprecated and will be removed in the future.\nUse ${NEW} instead\n") + set(${NEW} ON) + endif() +endfunction() + +whisper_option_depr(FATAL_ERROR WHISPER_CUBLAS GGML_CUDA) +whisper_option_depr(WARNING WHISPER_CUDA GGML_CUDA) +whisper_option_depr(WARNING WHISPER_KOMPUTE GGML_KOMPUTE) +whisper_option_depr(WARNING WHISPER_METAL GGML_METAL) +whisper_option_depr(WARNING WHISPER_METAL_EMBED_LIBRARY GGML_METAL_EMBED_LIBRARY) +whisper_option_depr(WARNING WHISPER_NATIVE GGML_NATIVE) +whisper_option_depr(WARNING WHISPER_OPENMP GGML_OPENMP) +whisper_option_depr(WARNING WHISPER_RPC GGML_RPC) +whisper_option_depr(WARNING WHISPER_SYCL GGML_SYCL) +whisper_option_depr(WARNING WHISPER_SYCL_F16 GGML_SYCL_F16) + +# +# build the library +# + +if (NOT TARGET ggml) + add_subdirectory(ggml) + # ... otherwise assume ggml is added by a parent CMakeLists.txt +endif() +add_subdirectory(src) + +# +# install +# + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +set(WHISPER_BUILD_NUMBER ${BUILD_NUMBER}) +set(WHISPER_BUILD_COMMIT ${BUILD_COMMIT}) +set(WHISPER_INSTALL_VERSION ${CMAKE_PROJECT_VERSION}) + +set(WHISPER_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Location of header files") +set(WHISPER_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of library files") +set(WHISPER_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Location of binary files") + +get_directory_property(WHISPER_TRANSIENT_DEFINES COMPILE_DEFINITIONS) + +set_target_properties(whisper PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/include/whisper.h) +install(TARGETS whisper LIBRARY PUBLIC_HEADER) + +configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/whisper-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/whisper-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/whisper + PATH_VARS + WHISPER_INCLUDE_INSTALL_DIR + WHISPER_LIB_INSTALL_DIR + WHISPER_BIN_INSTALL_DIR ) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/whisper-version.cmake + VERSION ${WHISPER_INSTALL_VERSION} + COMPATIBILITY SameMajorVersion) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/whisper-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/whisper-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/whisper) + +configure_file(cmake/whisper.pc.in + "${CMAKE_CURRENT_BINARY_DIR}/whisper.pc" + @ONLY) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/whisper.pc" + DESTINATION lib/pkgconfig) + +# +# programs, examples and tests +# + +if (WHISPER_BUILD_TESTS AND NOT CMAKE_JS_VERSION) + #include(CTest) + #add_subdirectory(tests) +endif () + +if (WHISPER_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..acb96ce78e0486e9dc7602cdcdd2f491c34f335a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-2024 The ggml authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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 OR COPYRIGHT HOLDERS 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. diff --git a/Makefile b/Makefile index d8ef07c8a240093fa2f17f562d6b3c94f7c461f2..3e359f2fe1ac8a511ca77f1805feb24108a02e46 100644 --- a/Makefile +++ b/Makefile @@ -971,7 +971,8 @@ $(LIB_WHISPER): \ $(CXX) $(CXXFLAGS) -shared -fPIC -o $@ $^ $(LDFLAGS) $(LIB_WHISPER_S): \ - $(OBJ_WHISPER) + $(OBJ_WHISPER) \ + $(OBJ_GGML) ar rcs $(LIB_WHISPER_S) $^ # common diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000000000000000000000000000000000000..f3893262c067bd976c605b5ca28c58881eac7d45 --- /dev/null +++ b/Package.swift @@ -0,0 +1,60 @@ +// swift-tools-version:5.5 + +import PackageDescription + +let package = Package( + name: "whisper", + platforms: [ + .macOS(.v12), + .iOS(.v14), + .watchOS(.v4), + .tvOS(.v14) + ], + products: [ + .library(name: "whisper", targets: ["whisper"]), + ], + targets: [ + .target( + name: "whisper", + path: ".", + exclude: [ + "bindings", + "cmake", + "coreml", + "examples", + "extra", + "models", + "samples", + "tests", + "CMakeLists.txt", + "Makefile" + ], + sources: [ + "ggml/src/ggml.c", + "src/whisper.cpp", + "ggml/src/ggml-aarch64.c", + "ggml/src/ggml-alloc.c", + "ggml/src/ggml-backend.c", + "ggml/src/ggml-quants.c", + "ggml/src/ggml-metal.m" + ], + resources: [.process("ggml-metal.metal")], + publicHeadersPath: "spm-headers", + cSettings: [ + .unsafeFlags(["-Wno-shorten-64-to-32", "-O3", "-DNDEBUG"]), + .define("GGML_USE_ACCELERATE"), + .unsafeFlags(["-fno-objc-arc"]), + .define("GGML_USE_METAL") + // NOTE: NEW_LAPACK will required iOS version 16.4+ + // We should consider add this in the future when we drop support for iOS 14 + // (ref: ref: https://developer.apple.com/documentation/accelerate/1513264-cblas_sgemm?language=objc) + // .define("ACCELERATE_NEW_LAPACK"), + // .define("ACCELERATE_LAPACK_ILP64") + ], + linkerSettings: [ + .linkedFramework("Accelerate") + ] + ) + ], + cxxLanguageStandard: .cxx11 +) diff --git a/README.md b/README.md index bbb299e533df6a3ed31f41c9bb2f98e85de41921..e9b5edf7da6a93411722132688e6650e3a40222e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,832 @@ +# whisper.cpp + +![whisper.cpp](https://user-images.githubusercontent.com/1991296/235238348-05d0f6a4-da44-4900-a1de-d0707e75b763.jpeg) + +[![Actions Status](https://github.com/ggerganov/whisper.cpp/workflows/CI/badge.svg)](https://github.com/ggerganov/whisper.cpp/actions) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![Conan Center](https://shields.io/conan/v/whisper-cpp)](https://conan.io/center/whisper-cpp) +[![npm](https://img.shields.io/npm/v/whisper.cpp.svg)](https://www.npmjs.com/package/whisper.cpp/) + +Stable: [v1.6.2](https://github.com/ggerganov/whisper.cpp/releases/tag/v1.6.0) / [Roadmap | F.A.Q.](https://github.com/ggerganov/whisper.cpp/discussions/126) + +High-performance inference of [OpenAI's Whisper](https://github.com/openai/whisper) automatic speech recognition (ASR) model: + +- Plain C/C++ implementation without dependencies +- Apple Silicon first-class citizen - optimized via ARM NEON, Accelerate framework, Metal and [Core ML](https://github.com/ggerganov/whisper.cpp#core-ml-support) +- AVX intrinsics support for x86 architectures +- VSX intrinsics support for POWER architectures +- Mixed F16 / F32 precision +- [4-bit and 5-bit integer quantization support](https://github.com/ggerganov/whisper.cpp#quantization) +- Zero memory allocations at runtime +- Support for CPU-only inference +- [Efficient GPU support for NVIDIA](https://github.com/ggerganov/whisper.cpp#nvidia-gpu-support-via-cublas) +- [OpenVINO Support](https://github.com/ggerganov/whisper.cpp#openvino-support) +- [C-style API](https://github.com/ggerganov/whisper.cpp/blob/master/whisper.h) + +Supported platforms: + +- [x] Mac OS (Intel and Arm) +- [x] [iOS](examples/whisper.objc) +- [x] [Android](examples/whisper.android) +- [x] [Java](bindings/java/README.md) +- [x] Linux / [FreeBSD](https://github.com/ggerganov/whisper.cpp/issues/56#issuecomment-1350920264) +- [x] [WebAssembly](examples/whisper.wasm) +- [x] Windows ([MSVC](https://github.com/ggerganov/whisper.cpp/blob/master/.github/workflows/build.yml#L117-L144) and [MinGW](https://github.com/ggerganov/whisper.cpp/issues/168)] +- [x] [Raspberry Pi](https://github.com/ggerganov/whisper.cpp/discussions/166) +- [x] [Docker](https://github.com/ggerganov/whisper.cpp/pkgs/container/whisper.cpp) + +The entire high-level implementation of the model is contained in [whisper.h](include/whisper.h) and [whisper.cpp](src/whisper.cpp). +The rest of the code is part of the [`ggml`](https://github.com/ggerganov/ggml) machine learning library. + +Having such a lightweight implementation of the model allows to easily integrate it in different platforms and applications. +As an example, here is a video of running the model on an iPhone 13 device - fully offline, on-device: [whisper.objc](examples/whisper.objc) + +https://user-images.githubusercontent.com/1991296/197385372-962a6dea-bca1-4d50-bf96-1d8c27b98c81.mp4 + +You can also easily make your own offline voice assistant application: [command](examples/command) + +https://user-images.githubusercontent.com/1991296/204038393-2f846eae-c255-4099-a76d-5735c25c49da.mp4 + +On Apple Silicon, the inference runs fully on the GPU via Metal: + +https://github.com/ggerganov/whisper.cpp/assets/1991296/c82e8f86-60dc-49f2-b048-d2fdbd6b5225 + +Or you can even run it straight in the browser: [talk.wasm](examples/talk.wasm) + +## Implementation details + +- The core tensor operations are implemented in C ([ggml.h](ggml/include/ggml.h) / [ggml.c](ggml/src/ggml.c)) +- The transformer model and the high-level C-style API are implemented in C++ ([whisper.h](include/whisper.h) / [whisper.cpp](src/whisper.cpp)) +- Sample usage is demonstrated in [main.cpp](examples/main) +- Sample real-time audio transcription from the microphone is demonstrated in [stream.cpp](examples/stream) +- Various other examples are available in the [examples](examples) folder + +The tensor operators are optimized heavily for Apple silicon CPUs. Depending on the computation size, Arm Neon SIMD intrinsics or CBLAS Accelerate framework routines are used. The latter are especially effective for bigger sizes since the Accelerate framework utilizes the special-purpose AMX coprocessor available in modern Apple products. + +## Quick start + +First clone the repository: + +```bash +git clone https://github.com/ggerganov/whisper.cpp.git +``` + +Then, download one of the Whisper [models](models/README.md) converted in [`ggml` format](#ggml-format). For example: + +```bash +bash ./models/download-ggml-model.sh base.en +``` + +Now build the [main](examples/main) example and transcribe an audio file like this: + +```bash +# build the main example +make + +# transcribe an audio file +./main -f samples/jfk.wav +``` + +--- + +For a quick demo, simply run `make base.en`: + +```text +$ make base.en + +cc -I. -O3 -std=c11 -pthread -DGGML_USE_ACCELERATE -c ggml.c -o ggml.o +c++ -I. -I./examples -O3 -std=c++11 -pthread -c whisper.cpp -o whisper.o +c++ -I. -I./examples -O3 -std=c++11 -pthread examples/main/main.cpp whisper.o ggml.o -o main -framework Accelerate +./main -h + +usage: ./main [options] file0.wav file1.wav ... + +options: + -h, --help [default] show this help message and exit + -t N, --threads N [4 ] number of threads to use during computation + -p N, --processors N [1 ] number of processors to use during computation + -ot N, --offset-t N [0 ] time offset in milliseconds + -on N, --offset-n N [0 ] segment index offset + -d N, --duration N [0 ] duration of audio to process in milliseconds + -mc N, --max-context N [-1 ] maximum number of text context tokens to store + -ml N, --max-len N [0 ] maximum segment length in characters + -sow, --split-on-word [false ] split on word rather than on token + -bo N, --best-of N [5 ] number of best candidates to keep + -bs N, --beam-size N [5 ] beam size for beam search + -wt N, --word-thold N [0.01 ] word timestamp probability threshold + -et N, --entropy-thold N [2.40 ] entropy threshold for decoder fail + -lpt N, --logprob-thold N [-1.00 ] log probability threshold for decoder fail + -debug, --debug-mode [false ] enable debug mode (eg. dump log_mel) + -tr, --translate [false ] translate from source language to english + -di, --diarize [false ] stereo audio diarization + -tdrz, --tinydiarize [false ] enable tinydiarize (requires a tdrz model) + -nf, --no-fallback [false ] do not use temperature fallback while decoding + -otxt, --output-txt [false ] output result in a text file + -ovtt, --output-vtt [false ] output result in a vtt file + -osrt, --output-srt [false ] output result in a srt file + -olrc, --output-lrc [false ] output result in a lrc file + -owts, --output-words [false ] output script for generating karaoke video + -fp, --font-path [/System/Library/Fonts/Supplemental/Courier New Bold.ttf] path to a monospace font for karaoke video + -ocsv, --output-csv [false ] output result in a CSV file + -oj, --output-json [false ] output result in a JSON file + -ojf, --output-json-full [false ] include more information in the JSON file + -of FNAME, --output-file FNAME [ ] output file path (without file extension) + -ps, --print-special [false ] print special tokens + -pc, --print-colors [false ] print colors + -pp, --print-progress [false ] print progress + -nt, --no-timestamps [false ] do not print timestamps + -l LANG, --language LANG [en ] spoken language ('auto' for auto-detect) + -dl, --detect-language [false ] exit after automatically detecting language + --prompt PROMPT [ ] initial prompt + -m FNAME, --model FNAME [models/ggml-base.en.bin] model path + -f FNAME, --file FNAME [ ] input WAV file path + -oved D, --ov-e-device DNAME [CPU ] the OpenVINO device used for encode inference + -ls, --log-score [false ] log best decoder scores of tokens + -ng, --no-gpu [false ] disable GPU + + +bash ./models/download-ggml-model.sh base.en +Downloading ggml model base.en ... +ggml-base.en.bin 100%[========================>] 141.11M 6.34MB/s in 24s +Done! Model 'base.en' saved in 'models/ggml-base.en.bin' +You can now use it like this: + + $ ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + +=============================================== +Running base.en on all samples in ./samples ... +=============================================== + +---------------------------------------------- +[+] Running base.en on samples/jfk.wav ... (run 'ffplay samples/jfk.wav' to listen) +---------------------------------------------- + +whisper_init_from_file: loading model from 'models/ggml-base.en.bin' +whisper_model_load: loading model +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 512 +whisper_model_load: n_audio_head = 8 +whisper_model_load: n_audio_layer = 6 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 512 +whisper_model_load: n_text_head = 8 +whisper_model_load: n_text_layer = 6 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 2 +whisper_model_load: mem required = 215.00 MB (+ 6.00 MB per decoder) +whisper_model_load: kv self size = 5.25 MB +whisper_model_load: kv cross size = 17.58 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: model ctx = 140.60 MB +whisper_model_load: model size = 140.54 MB + +system_info: n_threads = 4 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | + +main: processing 'samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + + +[00:00:00.000 --> 00:00:11.000] And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country. + + +whisper_print_timings: fallbacks = 0 p / 0 h +whisper_print_timings: load time = 113.81 ms +whisper_print_timings: mel time = 15.40 ms +whisper_print_timings: sample time = 11.58 ms / 27 runs ( 0.43 ms per run) +whisper_print_timings: encode time = 266.60 ms / 1 runs ( 266.60 ms per run) +whisper_print_timings: decode time = 66.11 ms / 27 runs ( 2.45 ms per run) +whisper_print_timings: total time = 476.31 ms +``` + +The command downloads the `base.en` model converted to custom `ggml` format and runs the inference on all `.wav` samples in the folder `samples`. + +For detailed usage instructions, run: `./main -h` + +Note that the [main](examples/main) example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool. +For example, you can use `ffmpeg` like this: + +```bash +ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav +``` + +## More audio samples + +If you want some extra audio samples to play with, simply run: + +``` +make samples +``` + +This will download a few more audio files from Wikipedia and convert them to 16-bit WAV format via `ffmpeg`. + +You can download and run the other models as follows: + +``` +make tiny.en +make tiny +make base.en +make base +make small.en +make small +make medium.en +make medium +make large-v1 +make large-v2 +make large-v3 +``` + +## Memory usage + +| Model | Disk | Mem | +| ------ | ------- | ------- | +| tiny | 75 MiB | ~273 MB | +| base | 142 MiB | ~388 MB | +| small | 466 MiB | ~852 MB | +| medium | 1.5 GiB | ~2.1 GB | +| large | 2.9 GiB | ~3.9 GB | + +## Quantization + +`whisper.cpp` supports integer quantization of the Whisper `ggml` models. +Quantized models require less memory and disk space and depending on the hardware can be processed more efficiently. + +Here are the steps for creating and using a quantized model: + +```bash +# quantize a model with Q5_0 method +make quantize +./quantize models/ggml-base.en.bin models/ggml-base.en-q5_0.bin q5_0 + +# run the examples as usual, specifying the quantized model file +./main -m models/ggml-base.en-q5_0.bin ./samples/gb0.wav +``` + +## Core ML support + +On Apple Silicon devices, the Encoder inference can be executed on the Apple Neural Engine (ANE) via Core ML. This can result in significant +speed-up - more than x3 faster compared with CPU-only execution. Here are the instructions for generating a Core ML model and using it with `whisper.cpp`: + +- Install Python dependencies needed for the creation of the Core ML model: + + ```bash + pip install ane_transformers + pip install openai-whisper + pip install coremltools + ``` + + - To ensure `coremltools` operates correctly, please confirm that [Xcode](https://developer.apple.com/xcode/) is installed and execute `xcode-select --install` to install the command-line tools. + - Python 3.10 is recommended. + - MacOS Sonoma (version 14) or newer is recommended, as older versions of MacOS might experience issues with transcription hallucination. + - [OPTIONAL] It is recommended to utilize a Python version management system, such as [Miniconda](https://docs.conda.io/en/latest/miniconda.html) for this step: + - To create an environment, use: `conda create -n py310-whisper python=3.10 -y` + - To activate the environment, use: `conda activate py310-whisper` + +- Generate a Core ML model. For example, to generate a `base.en` model, use: + + ```bash + ./models/generate-coreml-model.sh base.en + ``` + + This will generate the folder `models/ggml-base.en-encoder.mlmodelc` + +- Build `whisper.cpp` with Core ML support: + + ```bash + # using Makefile + make clean + WHISPER_COREML=1 make -j + + # using CMake + cmake -B build -DWHISPER_COREML=1 + cmake --build build -j --config Release + ``` + +- Run the examples as usual. For example: + + ```text + $ ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + ... + + whisper_init_state: loading Core ML model from 'models/ggml-base.en-encoder.mlmodelc' + whisper_init_state: first run on a device may take a while ... + whisper_init_state: Core ML model loaded + + system_info: n_threads = 4 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | COREML = 1 | + + ... + ``` + + The first run on a device is slow, since the ANE service compiles the Core ML model to some device-specific format. + Next runs are faster. + +For more information about the Core ML implementation please refer to PR [#566](https://github.com/ggerganov/whisper.cpp/pull/566). + +## OpenVINO support + +On platforms that support [OpenVINO](https://github.com/openvinotoolkit/openvino), the Encoder inference can be executed +on OpenVINO-supported devices including x86 CPUs and Intel GPUs (integrated & discrete). + +This can result in significant speedup in encoder performance. Here are the instructions for generating the OpenVINO model and using it with `whisper.cpp`: + +- First, setup python virtual env. and install python dependencies. Python 3.10 is recommended. + + Windows: + + ```powershell + cd models + python -m venv openvino_conv_env + openvino_conv_env\Scripts\activate + python -m pip install --upgrade pip + pip install -r requirements-openvino.txt + ``` + + Linux and macOS: + + ```bash + cd models + python3 -m venv openvino_conv_env + source openvino_conv_env/bin/activate + python -m pip install --upgrade pip + pip install -r requirements-openvino.txt + ``` + +- Generate an OpenVINO encoder model. For example, to generate a `base.en` model, use: + + ``` + python convert-whisper-to-openvino.py --model base.en + ``` + + This will produce ggml-base.en-encoder-openvino.xml/.bin IR model files. It's recommended to relocate these to the same folder as `ggml` models, as that + is the default location that the OpenVINO extension will search at runtime. + +- Build `whisper.cpp` with OpenVINO support: + + Download OpenVINO package from [release page](https://github.com/openvinotoolkit/openvino/releases). The recommended version to use is [2023.0.0](https://github.com/openvinotoolkit/openvino/releases/tag/2023.0.0). + + After downloading & extracting package onto your development system, set up required environment by sourcing setupvars script. For example: + + Linux: + + ```bash + source /path/to/l_openvino_toolkit_ubuntu22_2023.0.0.10926.b4452d56304_x86_64/setupvars.sh + ``` + + Windows (cmd): + + ```powershell + C:\Path\To\w_openvino_toolkit_windows_2023.0.0.10926.b4452d56304_x86_64\setupvars.bat + ``` + + And then build the project using cmake: + + ```bash + cmake -B build -DWHISPER_OPENVINO=1 + cmake --build build -j --config Release + ``` + +- Run the examples as usual. For example: + + ```text + $ ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + ... + + whisper_ctx_init_openvino_encoder: loading OpenVINO model from 'models/ggml-base.en-encoder-openvino.xml' + whisper_ctx_init_openvino_encoder: first run on a device may take a while ... + whisper_openvino_init: path_model = models/ggml-base.en-encoder-openvino.xml, device = GPU, cache_dir = models/ggml-base.en-encoder-openvino-cache + whisper_ctx_init_openvino_encoder: OpenVINO model loaded + + system_info: n_threads = 4 / 8 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | COREML = 0 | OPENVINO = 1 | + + ... + ``` + + The first time run on an OpenVINO device is slow, since the OpenVINO framework will compile the IR (Intermediate Representation) model to a device-specific 'blob'. This device-specific blob will get + cached for the next run. + +For more information about the Core ML implementation please refer to PR [#1037](https://github.com/ggerganov/whisper.cpp/pull/1037). + +## NVIDIA GPU support + +With NVIDIA cards the processing of the models is done efficiently on the GPU via cuBLAS and custom CUDA kernels. +First, make sure you have installed `cuda`: https://developer.nvidia.com/cuda-downloads + +Now build `whisper.cpp` with CUDA support: + +``` +make clean +GGML_CUDA=1 make -j +``` + +## BLAS CPU support via OpenBLAS + +Encoder processing can be accelerated on the CPU via OpenBLAS. +First, make sure you have installed `openblas`: https://www.openblas.net/ + +Now build `whisper.cpp` with OpenBLAS support: + +``` +make clean +GGML_OPENBLAS=1 make -j +``` + +## BLAS CPU support via Intel MKL + +Encoder processing can be accelerated on the CPU via the BLAS compatible interface of Intel's Math Kernel Library. +First, make sure you have installed Intel's MKL runtime and development packages: https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl-download.html + +Now build `whisper.cpp` with Intel MKL BLAS support: + +``` +source /opt/intel/oneapi/setvars.sh +mkdir build +cd build +cmake -DWHISPER_MKL=ON .. +WHISPER_MKL=1 make -j +``` + +## Docker + +### Prerequisites + +- Docker must be installed and running on your system. +- Create a folder to store big models & intermediate files (ex. /whisper/models) + +### Images + +We have two Docker images available for this project: + +1. `ghcr.io/ggerganov/whisper.cpp:main`: This image includes the main executable file as well as `curl` and `ffmpeg`. (platforms: `linux/amd64`, `linux/arm64`) +2. `ghcr.io/ggerganov/whisper.cpp:main-cuda`: Same as `main` but compiled with CUDA support. (platforms: `linux/amd64`) + +### Usage + +```shell +# download model and persist it in a local folder +docker run -it --rm \ + -v path/to/models:/models \ + whisper.cpp:main "./models/download-ggml-model.sh base /models" +# transcribe an audio file +docker run -it --rm \ + -v path/to/models:/models \ + -v path/to/audios:/audios \ + whisper.cpp:main "./main -m /models/ggml-base.bin -f /audios/jfk.wav" +# transcribe an audio file in samples folder +docker run -it --rm \ + -v path/to/models:/models \ + whisper.cpp:main "./main -m /models/ggml-base.bin -f ./samples/jfk.wav" +``` + +## Installing with Conan + +You can install pre-built binaries for whisper.cpp or build it from source using [Conan](https://conan.io/). Use the following command: + +``` +conan install --requires="whisper-cpp/[*]" --build=missing +``` + +For detailed instructions on how to use Conan, please refer to the [Conan documentation](https://docs.conan.io/2/). + +## Limitations + +- Inference only + +## Another example + +Here is another example of transcribing a [3:24 min speech](https://upload.wikimedia.org/wikipedia/commons/1/1f/George_W_Bush_Columbia_FINAL.ogg) +in about half a minute on a MacBook M1 Pro, using `medium.en` model: + +
+ Expand to see the result + +```text +$ ./main -m models/ggml-medium.en.bin -f samples/gb1.wav -t 8 + +whisper_init_from_file: loading model from 'models/ggml-medium.en.bin' +whisper_model_load: loading model +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 1024 +whisper_model_load: n_audio_head = 16 +whisper_model_load: n_audio_layer = 24 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 1024 +whisper_model_load: n_text_head = 16 +whisper_model_load: n_text_layer = 24 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 4 +whisper_model_load: mem required = 1720.00 MB (+ 43.00 MB per decoder) +whisper_model_load: kv self size = 42.00 MB +whisper_model_load: kv cross size = 140.62 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: model ctx = 1462.35 MB +whisper_model_load: model size = 1462.12 MB + +system_info: n_threads = 8 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | + +main: processing 'samples/gb1.wav' (3179750 samples, 198.7 sec), 8 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + + +[00:00:00.000 --> 00:00:08.000] My fellow Americans, this day has brought terrible news and great sadness to our country. +[00:00:08.000 --> 00:00:17.000] At nine o'clock this morning, Mission Control in Houston lost contact with our Space Shuttle Columbia. +[00:00:17.000 --> 00:00:23.000] A short time later, debris was seen falling from the skies above Texas. +[00:00:23.000 --> 00:00:29.000] The Columbia's lost. There are no survivors. +[00:00:29.000 --> 00:00:32.000] On board was a crew of seven. +[00:00:32.000 --> 00:00:39.000] Colonel Rick Husband, Lieutenant Colonel Michael Anderson, Commander Laurel Clark, +[00:00:39.000 --> 00:00:48.000] Captain David Brown, Commander William McCool, Dr. Kultna Shavla, and Ilan Ramon, +[00:00:48.000 --> 00:00:52.000] a colonel in the Israeli Air Force. +[00:00:52.000 --> 00:00:58.000] These men and women assumed great risk in the service to all humanity. +[00:00:58.000 --> 00:01:03.000] In an age when space flight has come to seem almost routine, +[00:01:03.000 --> 00:01:07.000] it is easy to overlook the dangers of travel by rocket +[00:01:07.000 --> 00:01:12.000] and the difficulties of navigating the fierce outer atmosphere of the Earth. +[00:01:12.000 --> 00:01:18.000] These astronauts knew the dangers, and they faced them willingly, +[00:01:18.000 --> 00:01:23.000] knowing they had a high and noble purpose in life. +[00:01:23.000 --> 00:01:31.000] Because of their courage and daring and idealism, we will miss them all the more. +[00:01:31.000 --> 00:01:36.000] All Americans today are thinking as well of the families of these men and women +[00:01:36.000 --> 00:01:40.000] who have been given this sudden shock and grief. +[00:01:40.000 --> 00:01:45.000] You're not alone. Our entire nation grieves with you, +[00:01:45.000 --> 00:01:52.000] and those you love will always have the respect and gratitude of this country. +[00:01:52.000 --> 00:01:56.000] The cause in which they died will continue. +[00:01:56.000 --> 00:02:04.000] Mankind is led into the darkness beyond our world by the inspiration of discovery +[00:02:04.000 --> 00:02:11.000] and the longing to understand. Our journey into space will go on. +[00:02:11.000 --> 00:02:16.000] In the skies today, we saw destruction and tragedy. +[00:02:16.000 --> 00:02:22.000] Yet farther than we can see, there is comfort and hope. +[00:02:22.000 --> 00:02:29.000] In the words of the prophet Isaiah, "Lift your eyes and look to the heavens +[00:02:29.000 --> 00:02:35.000] who created all these. He who brings out the starry hosts one by one +[00:02:35.000 --> 00:02:39.000] and calls them each by name." +[00:02:39.000 --> 00:02:46.000] Because of His great power and mighty strength, not one of them is missing. +[00:02:46.000 --> 00:02:55.000] The same Creator who names the stars also knows the names of the seven souls we mourn today. +[00:02:55.000 --> 00:03:01.000] The crew of the shuttle Columbia did not return safely to earth, +[00:03:01.000 --> 00:03:05.000] yet we can pray that all are safely home. +[00:03:05.000 --> 00:03:13.000] May God bless the grieving families, and may God continue to bless America. +[00:03:13.000 --> 00:03:19.000] [Silence] + + +whisper_print_timings: fallbacks = 1 p / 0 h +whisper_print_timings: load time = 569.03 ms +whisper_print_timings: mel time = 146.85 ms +whisper_print_timings: sample time = 238.66 ms / 553 runs ( 0.43 ms per run) +whisper_print_timings: encode time = 18665.10 ms / 9 runs ( 2073.90 ms per run) +whisper_print_timings: decode time = 13090.93 ms / 549 runs ( 23.85 ms per run) +whisper_print_timings: total time = 32733.52 ms +``` + +
+ +## Real-time audio input example + +This is a naive example of performing real-time inference on audio from your microphone. +The [stream](examples/stream) tool samples the audio every half a second and runs the transcription continuously. +More info is available in [issue #10](https://github.com/ggerganov/whisper.cpp/issues/10). + +```bash +make stream +./stream -m ./models/ggml-base.en.bin -t 8 --step 500 --length 5000 +``` + +https://user-images.githubusercontent.com/1991296/194935793-76afede7-cfa8-48d8-a80f-28ba83be7d09.mp4 + +## Confidence color-coding + +Adding the `--print-colors` argument will print the transcribed text using an experimental color coding strategy +to highlight words with high or low confidence: + +```bash +./main -m models/ggml-base.en.bin -f samples/gb0.wav --print-colors +``` + +image + +## Controlling the length of the generated text segments (experimental) + +For example, to limit the line length to a maximum of 16 characters, simply add `-ml 16`: + +```text +$ ./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 16 + +whisper_model_load: loading model from './models/ggml-base.en.bin' +... +system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + +[00:00:00.000 --> 00:00:00.850] And so my +[00:00:00.850 --> 00:00:01.590] fellow +[00:00:01.590 --> 00:00:04.140] Americans, ask +[00:00:04.140 --> 00:00:05.660] not what your +[00:00:05.660 --> 00:00:06.840] country can do +[00:00:06.840 --> 00:00:08.430] for you, ask +[00:00:08.430 --> 00:00:09.440] what you can do +[00:00:09.440 --> 00:00:10.020] for your +[00:00:10.020 --> 00:00:11.000] country. +``` + +## Word-level timestamp (experimental) + +The `--max-len` argument can be used to obtain word-level timestamps. Simply use `-ml 1`: + +```text +$ ./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 1 + +whisper_model_load: loading model from './models/ggml-base.en.bin' +... +system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + +[00:00:00.000 --> 00:00:00.320] +[00:00:00.320 --> 00:00:00.370] And +[00:00:00.370 --> 00:00:00.690] so +[00:00:00.690 --> 00:00:00.850] my +[00:00:00.850 --> 00:00:01.590] fellow +[00:00:01.590 --> 00:00:02.850] Americans +[00:00:02.850 --> 00:00:03.300] , +[00:00:03.300 --> 00:00:04.140] ask +[00:00:04.140 --> 00:00:04.990] not +[00:00:04.990 --> 00:00:05.410] what +[00:00:05.410 --> 00:00:05.660] your +[00:00:05.660 --> 00:00:06.260] country +[00:00:06.260 --> 00:00:06.600] can +[00:00:06.600 --> 00:00:06.840] do +[00:00:06.840 --> 00:00:07.010] for +[00:00:07.010 --> 00:00:08.170] you +[00:00:08.170 --> 00:00:08.190] , +[00:00:08.190 --> 00:00:08.430] ask +[00:00:08.430 --> 00:00:08.910] what +[00:00:08.910 --> 00:00:09.040] you +[00:00:09.040 --> 00:00:09.320] can +[00:00:09.320 --> 00:00:09.440] do +[00:00:09.440 --> 00:00:09.760] for +[00:00:09.760 --> 00:00:10.020] your +[00:00:10.020 --> 00:00:10.510] country +[00:00:10.510 --> 00:00:11.000] . +``` + +## Speaker segmentation via tinydiarize (experimental) + +More information about this approach is available here: https://github.com/ggerganov/whisper.cpp/pull/1058 + +Sample usage: + +```py +# download a tinydiarize compatible model +./models/download-ggml-model.sh small.en-tdrz + +# run as usual, adding the "-tdrz" command-line argument +./main -f ./samples/a13.wav -m ./models/ggml-small.en-tdrz.bin -tdrz +... +main: processing './samples/a13.wav' (480000 samples, 30.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, tdrz = 1, timestamps = 1 ... +... +[00:00:00.000 --> 00:00:03.800] Okay Houston, we've had a problem here. [SPEAKER_TURN] +[00:00:03.800 --> 00:00:06.200] This is Houston. Say again please. [SPEAKER_TURN] +[00:00:06.200 --> 00:00:08.260] Uh Houston we've had a problem. +[00:00:08.260 --> 00:00:11.320] We've had a main beam up on a volt. [SPEAKER_TURN] +[00:00:11.320 --> 00:00:13.820] Roger main beam interval. [SPEAKER_TURN] +[00:00:13.820 --> 00:00:15.100] Uh uh [SPEAKER_TURN] +[00:00:15.100 --> 00:00:18.020] So okay stand, by thirteen we're looking at it. [SPEAKER_TURN] +[00:00:18.020 --> 00:00:25.740] Okay uh right now uh Houston the uh voltage is uh is looking good um. +[00:00:27.620 --> 00:00:29.940] And we had a a pretty large bank or so. +``` + +## Karaoke-style movie generation (experimental) + +The [main](examples/main) example provides support for output of karaoke-style movies, where the +currently pronounced word is highlighted. Use the `-wts` argument and run the generated bash script. +This requires to have `ffmpeg` installed. + +Here are a few _"typical"_ examples: + +```bash +./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -owts +source ./samples/jfk.wav.wts +ffplay ./samples/jfk.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337465-dbee4b5e-9aeb-48a3-b1c6-323ac4db5b2c.mp4 + --- -title: AudioValidation -emoji: 🐨 -colorFrom: indigo -colorTo: gray -sdk: streamlit -sdk_version: 1.38.0 -app_file: app.py -pinned: false -license: apache-2.0 + +```bash +./main -m ./models/ggml-base.en.bin -f ./samples/mm0.wav -owts +source ./samples/mm0.wav.wts +ffplay ./samples/mm0.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337504-cc8fd233-0cb7-4920-95f9-4227de3570aa.mp4 + +--- + +```bash +./main -m ./models/ggml-base.en.bin -f ./samples/gb0.wav -owts +source ./samples/gb0.wav.wts +ffplay ./samples/gb0.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337538-b7b0c7a3-2753-4a88-a0cd-f28a317987ba.mp4 + --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +## Video comparison of different models + +Use the [scripts/bench-wts.sh](https://github.com/ggerganov/whisper.cpp/blob/master/scripts/bench-wts.sh) script to generate a video in the following format: + +```bash +./scripts/bench-wts.sh samples/jfk.wav +ffplay ./samples/jfk.wav.all.mp4 +``` + +https://user-images.githubusercontent.com/1991296/223206245-2d36d903-cf8e-4f09-8c3b-eb9f9c39d6fc.mp4 + +--- + +## Benchmarks + +In order to have an objective comparison of the performance of the inference across different system configurations, +use the [bench](examples/bench) tool. The tool simply runs the Encoder part of the model and prints how much time it +took to execute it. The results are summarized in the following Github issue: + +[Benchmark results](https://github.com/ggerganov/whisper.cpp/issues/89) + +Additionally a script to run whisper.cpp with different models and audio files is provided [bench.py](scripts/bench.py). + +You can run it with the following command, by default it will run against any standard model in the models folder. + +```bash +python3 scripts/bench.py -f samples/jfk.wav -t 2,4,8 -p 1,2 +``` + +It is written in python with the intention of being easy to modify and extend for your benchmarking use case. + +It outputs a csv file with the results of the benchmarking. + +## `ggml` format + +The original models are converted to a custom binary format. This allows to pack everything needed into a single file: + +- model parameters +- mel filters +- vocabulary +- weights + +You can download the converted models using the [models/download-ggml-model.sh](models/download-ggml-model.sh) script +or manually from here: + +- https://huggingface.co/ggerganov/whisper.cpp +- https://ggml.ggerganov.com + +For more details, see the conversion script [models/convert-pt-to-ggml.py](models/convert-pt-to-ggml.py) or [models/README.md](models/README.md). + +## [Bindings](https://github.com/ggerganov/whisper.cpp/discussions/categories/bindings) + +- [x] Rust: [tazz4843/whisper-rs](https://github.com/tazz4843/whisper-rs) | [#310](https://github.com/ggerganov/whisper.cpp/discussions/310) +- [x] JavaScript: [bindings/javascript](bindings/javascript) | [#309](https://github.com/ggerganov/whisper.cpp/discussions/309) + - React Native (iOS / Android): [whisper.rn](https://github.com/mybigday/whisper.rn) +- [x] Go: [bindings/go](bindings/go) | [#312](https://github.com/ggerganov/whisper.cpp/discussions/312) +- [x] Java: + - [GiviMAD/whisper-jni](https://github.com/GiviMAD/whisper-jni) +- [x] Ruby: [bindings/ruby](bindings/ruby) | [#507](https://github.com/ggerganov/whisper.cpp/discussions/507) +- [x] Objective-C / Swift: [ggerganov/whisper.spm](https://github.com/ggerganov/whisper.spm) | [#313](https://github.com/ggerganov/whisper.cpp/discussions/313) + - [exPHAT/SwiftWhisper](https://github.com/exPHAT/SwiftWhisper) +- [x] .NET: | [#422](https://github.com/ggerganov/whisper.cpp/discussions/422) + - [sandrohanea/whisper.net](https://github.com/sandrohanea/whisper.net) + - [NickDarvey/whisper](https://github.com/NickDarvey/whisper) +- [x] Python: | [#9](https://github.com/ggerganov/whisper.cpp/issues/9) + - [stlukey/whispercpp.py](https://github.com/stlukey/whispercpp.py) (Cython) + - [AIWintermuteAI/whispercpp](https://github.com/AIWintermuteAI/whispercpp) (Updated fork of aarnphm/whispercpp) + - [aarnphm/whispercpp](https://github.com/aarnphm/whispercpp) (Pybind11) +- [x] R: [bnosac/audio.whisper](https://github.com/bnosac/audio.whisper) +- [x] Unity: [macoron/whisper.unity](https://github.com/Macoron/whisper.unity) + +## Examples + +There are various examples of using the library for different projects in the [examples](examples) folder. +Some of the examples are even ported to run in the browser using WebAssembly. Check them out! + +| Example | Web | Description | +| --------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| [main](examples/main) | [whisper.wasm](examples/whisper.wasm) | Tool for translating and transcribing audio using Whisper | +| [bench](examples/bench) | [bench.wasm](examples/bench.wasm) | Benchmark the performance of Whisper on your machine | +| [stream](examples/stream) | [stream.wasm](examples/stream.wasm) | Real-time transcription of raw microphone capture | +| [command](examples/command) | [command.wasm](examples/command.wasm) | Basic voice assistant example for receiving voice commands from the mic | +| [wchess](examples/wchess) | [wchess.wasm](examples/wchess) | Voice-controlled chess | +| [talk](examples/talk) | [talk.wasm](examples/talk.wasm) | Talk with a GPT-2 bot | +| [talk-llama](examples/talk-llama) | | Talk with a LLaMA bot | +| [whisper.objc](examples/whisper.objc) | | iOS mobile application using whisper.cpp | +| [whisper.swiftui](examples/whisper.swiftui) | | SwiftUI iOS / macOS application using whisper.cpp | +| [whisper.android](examples/whisper.android) | | Android mobile application using whisper.cpp | +| [whisper.nvim](examples/whisper.nvim) | | Speech-to-text plugin for Neovim | +| [generate-karaoke.sh](examples/generate-karaoke.sh) | | Helper script to easily [generate a karaoke video](https://youtu.be/uj7hVta4blM) of raw audio capture | +| [livestream.sh](examples/livestream.sh) | | [Livestream audio transcription](https://github.com/ggerganov/whisper.cpp/issues/185) | +| [yt-wsp.sh](examples/yt-wsp.sh) | | Download + transcribe and/or translate any VOD [(original)](https://gist.github.com/DaniruKun/96f763ec1a037cc92fe1a059b643b818) | +| [server](examples/server) | | HTTP transcription server with OAI-like API | + +## [Discussions](https://github.com/ggerganov/whisper.cpp/discussions) + +If you have any kind of feedback about this project feel free to use the Discussions section and open a new topic. +You can use the [Show and tell](https://github.com/ggerganov/whisper.cpp/discussions/categories/show-and-tell) category +to share your own projects that use `whisper.cpp`. If you have a question, make sure to check the +[Frequently asked questions (#126)](https://github.com/ggerganov/whisper.cpp/discussions/126) discussion. diff --git a/README_sycl.md b/README_sycl.md new file mode 100644 index 0000000000000000000000000000000000000000..9ea2a7908ab8c0c8e1c68d7886ae94acd1907249 --- /dev/null +++ b/README_sycl.md @@ -0,0 +1,249 @@ +# whisper.cpp for SYCL + +[Background](#background) + +[OS](#os) + +[Intel GPU](#intel-gpu) + +[Linux](#linux) + +[Environment Variable](#environment-variable) + +[Known Issue](#known-issue) + +[Todo](#todo) + +## Background + +SYCL is a higher-level programming model to improve programming productivity on various hardware acceleratorssuch as CPUs, GPUs, and FPGAs. It is a single-source embedded domain-specific language based on pure C++17. + +oneAPI is a specification that is open and standards-based, supporting multiple architecture types including but not limited to GPU, CPU, and FPGA. The spec has both direct programming and API-based programming paradigms. + +Intel uses the SYCL as direct programming language to support CPU, GPUs and FPGAs. + +To avoid re-inventing the wheel, this code refers other code paths in llama.cpp (like OpenBLAS, cuBLAS, CLBlast). We use a open-source tool [SYCLomatic](https://github.com/oneapi-src/SYCLomatic) (Commercial release [Intel DPC++ Compatibility Tool](https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compatibility-tool.html)) migrate to SYCL. + +The whisper.cpp for SYCL is used to support Intel GPUs. + +For Intel CPU, recommend to use whisper.cpp for X86 (Intel MKL build). + +## OS + +|OS|Status|Verified| +|-|-|-| +|Linux|Support|Ubuntu 22.04| +|Windows|Ongoing| | + + +## Intel GPU + +|Intel GPU| Status | Verified Model| +|-|-|-| +|Intel Data Center Max Series| Support| Max 1550| +|Intel Data Center Flex Series| Support| Flex 170| +|Intel Arc Series| Support| Arc 770| +|Intel built-in Arc GPU| Support| built-in Arc GPU in Meteor Lake| +|Intel iGPU| Support| iGPU in i5-1250P, i7-1165G7| + + +## Linux + +### Setup Environment + +1. Install Intel GPU driver. + +a. Please install Intel GPU driver by official guide: [Install GPU Drivers](https://dgpu-docs.intel.com/driver/installation.html). + +Note: for iGPU, please install the client GPU driver. + +b. Add user to group: video, render. + +``` +sudo usermod -aG render username +sudo usermod -aG video username +``` + +Note: re-login to enable it. + +c. Check + +``` +sudo apt install clinfo +sudo clinfo -l +``` + +Output (example): + +``` +Platform #0: Intel(R) OpenCL Graphics + `-- Device #0: Intel(R) Arc(TM) A770 Graphics + + +Platform #0: Intel(R) OpenCL HD Graphics + `-- Device #0: Intel(R) Iris(R) Xe Graphics [0x9a49] +``` + +2. Install Intel oneAPI Base toolkit. + + +a. Please follow the procedure in [Get the Intel oneAPI Base Toolkit ](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html). + +Recommend to install to default folder: **/opt/intel/oneapi**. + +Following guide use the default folder as example. If you use other folder, please modify the following guide info with your folder. + +b. Check + +``` +source /opt/intel/oneapi/setvars.sh + +sycl-ls +``` + +There should be one or more level-zero devices. Like **[ext_oneapi_level_zero:gpu:0]**. + +Output (example): +``` +[opencl:acc:0] Intel(R) FPGA Emulation Platform for OpenCL(TM), Intel(R) FPGA Emulation Device OpenCL 1.2 [2023.16.10.0.17_160000] +[opencl:cpu:1] Intel(R) OpenCL, 13th Gen Intel(R) Core(TM) i7-13700K OpenCL 3.0 (Build 0) [2023.16.10.0.17_160000] +[opencl:gpu:2] Intel(R) OpenCL Graphics, Intel(R) Arc(TM) A770 Graphics OpenCL 3.0 NEO [23.30.26918.50] +[ext_oneapi_level_zero:gpu:0] Intel(R) Level-Zero, Intel(R) Arc(TM) A770 Graphics 1.3 [1.3.26918] + +``` + +2. Build locally: + +``` +mkdir -p build +cd build +source /opt/intel/oneapi/setvars.sh + +#for FP16 +#cmake .. -DWHISPER_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DWHISPER_SYCL_F16=ON + +#for FP32 +cmake .. -DWHISPER_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx + +#build example/main only +#cmake --build . --config Release --target main + +#build all binary +cmake --build . --config Release -v + +``` + +or + +``` +./examples/sycl/build.sh +``` + +Note: + +- By default, it will build for all binary files. It will take more time. To reduce the time, we recommend to build for **example/main** only. + +### Run + +1. Put model file to folder **models** + +2. Enable oneAPI running environment + +``` +source /opt/intel/oneapi/setvars.sh +``` + +3. List device ID + +Run without parameter: + +``` +./build/bin/ls-sycl-device + +or + +./build/bin/main +``` + +Check the ID in startup log, like: + +``` +found 4 SYCL devices: + Device 0: Intel(R) Arc(TM) A770 Graphics, compute capability 1.3, + max compute_units 512, max work group size 1024, max sub group size 32, global mem size 16225243136 + Device 1: Intel(R) FPGA Emulation Device, compute capability 1.2, + max compute_units 24, max work group size 67108864, max sub group size 64, global mem size 67065057280 + Device 2: 13th Gen Intel(R) Core(TM) i7-13700K, compute capability 3.0, + max compute_units 24, max work group size 8192, max sub group size 64, global mem size 67065057280 + Device 3: Intel(R) Arc(TM) A770 Graphics, compute capability 3.0, + max compute_units 512, max work group size 1024, max sub group size 32, global mem size 16225243136 + +``` + +|Attribute|Note| +|-|-| +|compute capability 1.3|Level-zero running time, recommended | +|compute capability 3.0|OpenCL running time, slower than level-zero in most cases| + +4. Set device ID and execute whisper.cpp + +Set device ID = 0 by **GGML_SYCL_DEVICE=0** + +``` +GGML_SYCL_DEVICE=0 ./build/bin/main -m models/ggml-base.en.bin -f samples/jfk.wav +``` +or run by script: + +``` +./examples/sycl/run_whisper.sh +``` + + + +5. Check the device ID in output + +Like: +``` +Using device **0** (Intel(R) Arc(TM) A770 Graphics) as main device +``` + + +## Environment Variable + +#### Build + +|Name|Value|Function| +|-|-|-| +|WHISPER_SYCL|ON (mandatory)|Enable build with SYCL code path.
For FP32/FP16, WHISPER_SYCL=ON is mandatory.| +|WHISPER_SYCL_F16|ON (optional)|Enable FP16 build with SYCL code path.For FP32, do not set it.| +|CMAKE_C_COMPILER|icx|Use icx compiler for SYCL code path| +|CMAKE_CXX_COMPILER|icpx|use icpx for SYCL code path| + +#### Running + + +|Name|Value|Function| +|-|-|-| +|GGML_SYCL_DEVICE|0 (default) or 1|Set the device id used. Check the device ids by default running output| +|GGML_SYCL_DEBUG|0 (default) or 1|Enable log function by macro: GGML_SYCL_DEBUG| + +## Known Issue + +- Error: `error while loading shared libraries: libsycl.so.7: cannot open shared object file: No such file or directory`. + + Miss to enable oneAPI running environment. + + Install oneAPI base toolkit and enable it by: `source /opt/intel/oneapi/setvars.sh`. + + +- Hang during startup + + llama.cpp use mmap as default way to read model file and copy to GPU. In some system, memcpy will be abnormal and block. + + Solution: add **--no-mmap**. + +## Todo + +- Support to build in Windows. + +- Support multiple cards. \ No newline at end of file diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..af79c51bc1f95e28c3a0b4639fce5d682b3e40ab --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,19 @@ +if (EMSCRIPTEN) + add_subdirectory(javascript) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/javascript/publish.log + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/whisper.js + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/libwhisper.worker.js + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/package.json + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/javascript + COMMAND npm publish + COMMAND touch publish.log + COMMENT "Publishing npm module v${PROJECT_VERSION}" + VERBATIM + ) + + add_custom_target(publish-npm + DEPENDS javascript/publish.log + ) +endif() diff --git a/bindings/go/.gitignore b/bindings/go/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..036df1d3b0d5dc58847078850c8b62ebb12b2b1d --- /dev/null +++ b/bindings/go/.gitignore @@ -0,0 +1,2 @@ +build +models diff --git a/bindings/go/LICENSE b/bindings/go/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..a8f0d7b9c9d372376eca572dd226b6dcfeddb43a --- /dev/null +++ b/bindings/go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 David Thorpe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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 OR COPYRIGHT HOLDERS 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. diff --git a/bindings/go/Makefile b/bindings/go/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..20a054c116fe2637a6bbe1708a96f4fc303146d6 --- /dev/null +++ b/bindings/go/Makefile @@ -0,0 +1,64 @@ +ifndef UNAME_S +UNAME_S := $(shell uname -s) +endif + +ifndef UNAME_P +UNAME_P := $(shell uname -p) +endif + +ifndef UNAME_M +UNAME_M := $(shell uname -m) +endif + +GGML_METAL_PATH_RESOURCES := $(abspath ../..) +BUILD_DIR := build +MODELS_DIR := models +EXAMPLES_DIR := $(wildcard examples/*) +INCLUDE_PATH := $(abspath ../../include):$(abspath ../../ggml/include) +LIBRARY_PATH := $(abspath ../..) + +ifeq ($(UNAME_S),Darwin) + EXT_LDFLAGS := -framework Foundation -framework Metal -framework MetalKit +endif + +all: clean whisper examples + +whisper: mkdir + @echo Build whisper + @${MAKE} -C ../.. libwhisper.a + +test: model-small whisper modtidy +ifeq ($(UNAME_S),Darwin) + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v . + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v ./pkg/whisper/... +else + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v . + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v ./pkg/whisper/... +endif + +examples: $(EXAMPLES_DIR) + +model-small: mkdir examples/go-model-download + @${BUILD_DIR}/go-model-download -out models ggml-small.en.bin + +$(EXAMPLES_DIR): mkdir whisper modtidy + @echo Build example $(notdir $@) +ifeq ($(UNAME_S),Darwin) + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go build ${BUILD_FLAGS} -ldflags "-extldflags '$(EXT_LDFLAGS)'" -o ${BUILD_DIR}/$(notdir $@) ./$@ +else + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go build ${BUILD_FLAGS} -o ${BUILD_DIR}/$(notdir $@) ./$@ +endif + +mkdir: + @echo Mkdir ${BUILD_DIR} + @install -d ${BUILD_DIR} + @echo Mkdir ${MODELS_DIR} + @install -d ${MODELS_DIR} + +modtidy: + @go mod tidy + +clean: + @echo Clean + @rm -fr $(BUILD_DIR) + @go clean diff --git a/bindings/go/README.md b/bindings/go/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1968cfd24700be7acdf5d54b9044b520e1425911 --- /dev/null +++ b/bindings/go/README.md @@ -0,0 +1,100 @@ +# Go bindings for Whisper + +This package provides Go bindings for whisper.cpp. They have been tested on: + + * Darwin (OS X) 12.6 on x64_64 + * Debian Linux on arm64 + * Fedora Linux on x86_64 + +The "low level" bindings are in the `bindings/go` directory and there is a more +Go-style package in the `bindings/go/pkg/whisper` directory. The most simple usage +is as follows: + +```go +import ( + "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +func main() { + var modelpath string // Path to the model + var samples []float32 // Samples to process + + // Load the model + model, err := whisper.New(modelpath) + if err != nil { + panic(err) + } + defer model.Close() + + // Process samples + context, err := model.NewContext() + if err != nil { + panic(err) + } + if err := context.Process(samples, nil, nil); err != nil { + return err + } + + // Print out the results + for { + segment, err := context.NextSegment() + if err != nil { + break + } + fmt.Printf("[%6s->%6s] %s\n", segment.Start, segment.End, segment.Text) + } +} +``` + +## Building & Testing + +In order to build, you need to have the Go compiler installed. You can get it from [here](https://golang.org/dl/). Run the tests with: + +```bash +git clone https://github.com/ggerganov/whisper.cpp.git +cd whisper.cpp/bindings/go +make test +``` + +This will compile a static `libwhisper.a` in a `build` folder, download a model file, then run the tests. To build the examples: + +```bash +make examples +``` + +The examples are placed in the `build` directory. Once built, you can download all the models with the following command: + +```bash +./build/go-model-download -out models +``` + +And you can then test a model against samples with the following command: + +```bash +./build/go-whisper -model models/ggml-tiny.en.bin samples/jfk.wav +``` + +## Using the bindings + +To use the bindings in your own software, + + 1. Import `github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper` (or `github.com/ggerganov/whisper.cpp/bindings/go` into your package; + 2. Compile `libwhisper.a` (you can use `make whisper` in the `bindings/go` directory); + 3. Link your go binary against whisper by setting the environment variables `C_INCLUDE_PATH` and `LIBRARY_PATH` + to point to the `whisper.h` file directory and `libwhisper.a` file directory respectively. + +Look at the `Makefile` in the `bindings/go` directory for an example. + +The API Documentation: + + * https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go + * https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper + +Getting help: + + * Follow the discussion for the go bindings [here](https://github.com/ggerganov/whisper.cpp/discussions/312) + +## License + +The license for the Go bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details. + diff --git a/bindings/go/doc.go b/bindings/go/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..dcc351f2732f92782c195c2d1e1d09640968b983 --- /dev/null +++ b/bindings/go/doc.go @@ -0,0 +1,5 @@ +/* +github.com/ggerganov/whisper.cpp/bindings/go +provides a speech-to-text service bindings for the Go programming language. +*/ +package whisper diff --git a/bindings/go/examples/go-model-download/context.go b/bindings/go/examples/go-model-download/context.go new file mode 100644 index 0000000000000000000000000000000000000000..639d8f5bd96dd2cf141941929250ecf9ff1e302e --- /dev/null +++ b/bindings/go/examples/go-model-download/context.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "os" + "os/signal" +) + +// ContextForSignal returns a context object which is cancelled when a signal +// is received. It returns nil if no signal parameter is provided +func ContextForSignal(signals ...os.Signal) context.Context { + if len(signals) == 0 { + return nil + } + + ch := make(chan os.Signal) + ctx, cancel := context.WithCancel(context.Background()) + + // Send message on channel when signal received + signal.Notify(ch, signals...) + + // When any signal received, call cancel + go func() { + <-ch + cancel() + }() + + // Return success + return ctx +} diff --git a/bindings/go/examples/go-model-download/main.go b/bindings/go/examples/go-model-download/main.go new file mode 100644 index 0000000000000000000000000000000000000000..3522d881717b42246a5c41c2da0b3af6575b9262 --- /dev/null +++ b/bindings/go/examples/go-model-download/main.go @@ -0,0 +1,208 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" + "syscall" + "time" +) + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +const ( + srcUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main" // The location of the models + srcExt = ".bin" // Filename extension + bufSize = 1024 * 64 // Size of the buffer used for downloading the model +) + +var ( + // The models which will be downloaded, if no model is specified as an argument + modelNames = []string{"ggml-tiny.en", "ggml-tiny", "ggml-base.en", "ggml-base", "ggml-small.en", "ggml-small", "ggml-medium.en", "ggml-medium", "ggml-large-v1", "ggml-large-v2", "ggml-large-v3"} +) + +var ( + // The output folder. When not set, use current working directory. + flagOut = flag.String("out", "", "Output folder") + + // HTTP timeout parameter - will timeout if takes longer than this to download a model + flagTimeout = flag.Duration("timeout", 30*time.Minute, "HTTP timeout") + + // Quiet parameter - will not print progress if set + flagQuiet = flag.Bool("quiet", false, "Quiet mode") +) + +/////////////////////////////////////////////////////////////////////////////// +// MAIN + +func main() { + flag.Usage = func() { + name := filepath.Base(flag.CommandLine.Name()) + fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] \n\n", name) + flag.PrintDefaults() + } + flag.Parse() + + // Get output path + out, err := GetOut() + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(-1) + } + + // Create context which quits on SIGINT or SIGQUIT + ctx := ContextForSignal(os.Interrupt, syscall.SIGQUIT) + + // Progress filehandle + progress := os.Stdout + if *flagQuiet { + progress, err = os.Open(os.DevNull) + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(-1) + } + defer progress.Close() + } + + // Download models - exit on error or interrupt + for _, model := range GetModels() { + url, err := URLForModel(model) + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + continue + } else if path, err := Download(ctx, progress, url, out); err == nil || err == io.EOF { + continue + } else if err == context.Canceled { + os.Remove(path) + fmt.Fprintln(progress, "\nInterrupted") + break + } else if err == context.DeadlineExceeded { + os.Remove(path) + fmt.Fprintln(progress, "Timeout downloading model") + continue + } else { + os.Remove(path) + fmt.Fprintln(os.Stderr, "Error:", err) + break + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// GetOut returns the path to the output directory +func GetOut() (string, error) { + if *flagOut == "" { + return os.Getwd() + } + if info, err := os.Stat(*flagOut); err != nil { + return "", err + } else if !info.IsDir() { + return "", fmt.Errorf("not a directory: %s", info.Name()) + } else { + return *flagOut, nil + } +} + +// GetModels returns the list of models to download +func GetModels() []string { + if flag.NArg() == 0 { + return modelNames + } else { + return flag.Args() + } +} + +// URLForModel returns the URL for the given model on huggingface.co +func URLForModel(model string) (string, error) { + if filepath.Ext(model) != srcExt { + model += srcExt + } + url, err := url.Parse(srcUrl) + if err != nil { + return "", err + } else { + url.Path = filepath.Join(url.Path, model) + } + return url.String(), nil +} + +// Download downloads the model from the given URL to the given output directory +func Download(ctx context.Context, p io.Writer, model, out string) (string, error) { + // Create HTTP client + client := http.Client{ + Timeout: *flagTimeout, + } + + // Initiate the download + req, err := http.NewRequest("GET", model, nil) + if err != nil { + return "", err + } + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("%s: %s", model, resp.Status) + } + + // If output file exists and is the same size as the model, skip + path := filepath.Join(out, filepath.Base(model)) + if info, err := os.Stat(path); err == nil && info.Size() == resp.ContentLength { + fmt.Fprintln(p, "Skipping", model, "as it already exists") + return "", nil + } + + // Create file + w, err := os.Create(path) + if err != nil { + return "", err + } + defer w.Close() + + // Report + fmt.Fprintln(p, "Downloading", model, "to", out) + + // Progressively download the model + data := make([]byte, bufSize) + count, pct := int64(0), int64(0) + ticker := time.NewTicker(5 * time.Second) + for { + select { + case <-ctx.Done(): + // Cancelled, return error + return path, ctx.Err() + case <-ticker.C: + pct = DownloadReport(p, pct, count, resp.ContentLength) + default: + // Read body + n, err := resp.Body.Read(data) + if err != nil { + DownloadReport(p, pct, count, resp.ContentLength) + return path, err + } else if m, err := w.Write(data[:n]); err != nil { + return path, err + } else { + count += int64(m) + } + } + } +} + +// Report periodically reports the download progress when percentage changes +func DownloadReport(w io.Writer, pct, count, total int64) int64 { + pct_ := count * 100 / total + if pct_ > pct { + fmt.Fprintf(w, " ...%d MB written (%d%%)\n", count/1e6, pct_) + } + return pct_ +} diff --git a/bindings/go/examples/go-whisper/color.go b/bindings/go/examples/go-whisper/color.go new file mode 100644 index 0000000000000000000000000000000000000000..fa5ac2f26ba83734b2236f9130101d619d5b2a3f --- /dev/null +++ b/bindings/go/examples/go-whisper/color.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +const ( + Reset = "\033[0m" + RGBPrefix = "\033[38;5;" // followed by RGB values in decimal format separated by colons + RGBSuffix = "m" +) + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Colorize text with RGB values, from 0 to 23 +func Colorize(text string, v int) string { + // https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + // Grayscale colors are in the range 232-255 + return RGBPrefix + fmt.Sprint(v%24+232) + RGBSuffix + text + Reset +} diff --git a/bindings/go/examples/go-whisper/flags.go b/bindings/go/examples/go-whisper/flags.go new file mode 100644 index 0000000000000000000000000000000000000000..766c92f1827e3af7f4cb514920ae347baacb530b --- /dev/null +++ b/bindings/go/examples/go-whisper/flags.go @@ -0,0 +1,147 @@ +package main + +import ( + "flag" + "fmt" + "strings" + "time" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type Flags struct { + *flag.FlagSet +} + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func NewFlags(name string, args []string) (*Flags, error) { + flags := &Flags{ + FlagSet: flag.NewFlagSet(name, flag.ContinueOnError), + } + + // Register the command line arguments + registerFlags(flags) + + // Parse command line + if err := flags.Parse(args); err != nil { + return nil, err + } + + // Return success + return flags, nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +func (flags *Flags) GetModel() string { + return flags.Lookup("model").Value.String() +} + +func (flags *Flags) GetLanguage() string { + return flags.Lookup("language").Value.String() +} + +func (flags *Flags) IsTranslate() bool { + return flags.Lookup("translate").Value.(flag.Getter).Get().(bool) +} + +func (flags *Flags) GetOffset() time.Duration { + return flags.Lookup("offset").Value.(flag.Getter).Get().(time.Duration) +} + +func (flags *Flags) GetDuration() time.Duration { + return flags.Lookup("duration").Value.(flag.Getter).Get().(time.Duration) +} + +func (flags *Flags) GetThreads() uint { + return flags.Lookup("threads").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetOut() string { + return strings.ToLower(flags.Lookup("out").Value.String()) +} + +func (flags *Flags) IsTokens() bool { + return flags.Lookup("tokens").Value.String() == "true" +} + +func (flags *Flags) IsColorize() bool { + return flags.Lookup("colorize").Value.String() == "true" +} + +func (flags *Flags) GetMaxLen() uint { + return flags.Lookup("max-len").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetMaxTokens() uint { + return flags.Lookup("max-tokens").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetWordThreshold() float32 { + return float32(flags.Lookup("word-thold").Value.(flag.Getter).Get().(float64)) +} + +func (flags *Flags) SetParams(context whisper.Context) error { + if lang := flags.GetLanguage(); lang != "" && lang != "auto" { + fmt.Fprintf(flags.Output(), "Setting language to %q\n", lang) + if err := context.SetLanguage(lang); err != nil { + return err + } + } + if flags.IsTranslate() && context.IsMultilingual() { + fmt.Fprintf(flags.Output(), "Setting translate to true\n") + context.SetTranslate(true) + } + if offset := flags.GetOffset(); offset != 0 { + fmt.Fprintf(flags.Output(), "Setting offset to %v\n", offset) + context.SetOffset(offset) + } + if duration := flags.GetDuration(); duration != 0 { + fmt.Fprintf(flags.Output(), "Setting duration to %v\n", duration) + context.SetDuration(duration) + } + if threads := flags.GetThreads(); threads != 0 { + fmt.Fprintf(flags.Output(), "Setting threads to %d\n", threads) + context.SetThreads(threads) + } + if max_len := flags.GetMaxLen(); max_len != 0 { + fmt.Fprintf(flags.Output(), "Setting max_segment_length to %d\n", max_len) + context.SetMaxSegmentLength(max_len) + } + if max_tokens := flags.GetMaxTokens(); max_tokens != 0 { + fmt.Fprintf(flags.Output(), "Setting max_tokens to %d\n", max_tokens) + context.SetMaxTokensPerSegment(max_tokens) + } + if word_threshold := flags.GetWordThreshold(); word_threshold != 0 { + fmt.Fprintf(flags.Output(), "Setting word_threshold to %f\n", word_threshold) + context.SetTokenThreshold(word_threshold) + } + + // Return success + return nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func registerFlags(flag *Flags) { + flag.String("model", "", "Path to the model file") + flag.String("language", "", "Spoken language") + flag.Bool("translate", false, "Translate from source language to english") + flag.Duration("offset", 0, "Time offset") + flag.Duration("duration", 0, "Duration of audio to process") + flag.Uint("threads", 0, "Number of threads to use") + flag.Uint("max-len", 0, "Maximum segment length in characters") + flag.Uint("max-tokens", 0, "Maximum tokens per segment") + flag.Float64("word-thold", 0, "Maximum segment score") + flag.Bool("tokens", false, "Display tokens") + flag.Bool("colorize", false, "Colorize tokens") + flag.String("out", "", "Output format (srt, none or leave as empty string)") +} diff --git a/bindings/go/examples/go-whisper/main.go b/bindings/go/examples/go-whisper/main.go new file mode 100644 index 0000000000000000000000000000000000000000..1bff7f5d50ae7dbe0dbfdffb40c0d301973bc328 --- /dev/null +++ b/bindings/go/examples/go-whisper/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +func main() { + flags, err := NewFlags(filepath.Base(os.Args[0]), os.Args[1:]) + if err == flag.ErrHelp { + os.Exit(0) + } else if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } else if flags.GetModel() == "" { + fmt.Fprintln(os.Stderr, "Use -model flag to specify which model file to use") + os.Exit(1) + } else if flags.NArg() == 0 { + fmt.Fprintln(os.Stderr, "No input files specified") + os.Exit(1) + } + + // Load model + model, err := whisper.New(flags.GetModel()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer model.Close() + + // Process files + for _, filename := range flags.Args() { + if err := Process(model, filename, flags); err != nil { + fmt.Fprintln(os.Stderr, err) + continue + } + } +} diff --git a/bindings/go/examples/go-whisper/process.go b/bindings/go/examples/go-whisper/process.go new file mode 100644 index 0000000000000000000000000000000000000000..71e52f0100069191c1321098d15f6df7b401b836 --- /dev/null +++ b/bindings/go/examples/go-whisper/process.go @@ -0,0 +1,132 @@ +package main + +import ( + "fmt" + "io" + "os" + "time" + + // Package imports + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" + wav "github.com/go-audio/wav" +) + +func Process(model whisper.Model, path string, flags *Flags) error { + var data []float32 + + // Create processing context + context, err := model.NewContext() + if err != nil { + return err + } + + // Set the parameters + if err := flags.SetParams(context); err != nil { + return err + } + + fmt.Printf("\n%s\n", context.SystemInfo()) + + // Open the file + fmt.Fprintf(flags.Output(), "Loading %q\n", path) + fh, err := os.Open(path) + if err != nil { + return err + } + defer fh.Close() + + // Decode the WAV file - load the full buffer + dec := wav.NewDecoder(fh) + if buf, err := dec.FullPCMBuffer(); err != nil { + return err + } else if dec.SampleRate != whisper.SampleRate { + return fmt.Errorf("unsupported sample rate: %d", dec.SampleRate) + } else if dec.NumChans != 1 { + return fmt.Errorf("unsupported number of channels: %d", dec.NumChans) + } else { + data = buf.AsFloat32Buffer().Data + } + + // Segment callback when -tokens is specified + var cb whisper.SegmentCallback + if flags.IsTokens() { + cb = func(segment whisper.Segment) { + fmt.Fprintf(flags.Output(), "%02d [%6s->%6s] ", segment.Num, segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond)) + for _, token := range segment.Tokens { + if flags.IsColorize() && context.IsText(token) { + fmt.Fprint(flags.Output(), Colorize(token.Text, int(token.P*24.0)), " ") + } else { + fmt.Fprint(flags.Output(), token.Text, " ") + } + } + fmt.Fprintln(flags.Output(), "") + fmt.Fprintln(flags.Output(), "") + } + } + + // Process the data + fmt.Fprintf(flags.Output(), " ...processing %q\n", path) + context.ResetTimings() + if err := context.Process(data, cb, nil); err != nil { + return err + } + + context.PrintTimings() + + // Print out the results + switch { + case flags.GetOut() == "srt": + return OutputSRT(os.Stdout, context) + case flags.GetOut() == "none": + return nil + default: + return Output(os.Stdout, context, flags.IsColorize()) + } +} + +// Output text as SRT file +func OutputSRT(w io.Writer, context whisper.Context) error { + n := 1 + for { + segment, err := context.NextSegment() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + fmt.Fprintln(w, n) + fmt.Fprintln(w, srtTimestamp(segment.Start), " --> ", srtTimestamp(segment.End)) + fmt.Fprintln(w, segment.Text) + fmt.Fprintln(w, "") + n++ + } +} + +// Output text to terminal +func Output(w io.Writer, context whisper.Context, colorize bool) error { + for { + segment, err := context.NextSegment() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + fmt.Fprintf(w, "[%6s->%6s]", segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond)) + if colorize { + for _, token := range segment.Tokens { + if !context.IsText(token) { + continue + } + fmt.Fprint(w, " ", Colorize(token.Text, int(token.P*24.0))) + } + fmt.Fprint(w, "\n") + } else { + fmt.Fprintln(w, " ", segment.Text) + } + } +} + +// Return srtTimestamp +func srtTimestamp(t time.Duration) string { + return fmt.Sprintf("%02d:%02d:%02d,%03d", t/time.Hour, (t%time.Hour)/time.Minute, (t%time.Minute)/time.Second, (t%time.Second)/time.Millisecond) +} diff --git a/bindings/go/go.mod b/bindings/go/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..594f184baaee05946f147a38b1fc33c82e55438d --- /dev/null +++ b/bindings/go/go.mod @@ -0,0 +1,16 @@ +module github.com/ggerganov/whisper.cpp/bindings/go + +go 1.19 + +require ( + github.com/go-audio/wav v1.1.0 + github.com/stretchr/testify v1.8.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-audio/audio v1.0.0 // indirect + github.com/go-audio/riff v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/bindings/go/go.sum b/bindings/go/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..870ebdc3c57714be92e180addc14e7dad6d4e4eb --- /dev/null +++ b/bindings/go/go.sum @@ -0,0 +1,23 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4= +github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs= +github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA= +github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498= +github.com/go-audio/wav v1.1.0 h1:jQgLtbqBzY7G+BM8fXF7AHUk1uHUviWS4X39d5rsL2g= +github.com/go-audio/wav v1.1.0/go.mod h1:mpe9qfwbScEbkd8uybLuIpTgHyrISw/OTuvjUW2iGtE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/bindings/go/params.go b/bindings/go/params.go new file mode 100644 index 0000000000000000000000000000000000000000..9c075b6a2cbd8457ae040d0c5ef2bb748447f555 --- /dev/null +++ b/bindings/go/params.go @@ -0,0 +1,192 @@ +package whisper + +import ( + "fmt" +) + +/////////////////////////////////////////////////////////////////////////////// +// CGO + +/* +#include +*/ +import "C" + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +func (p *Params) SetTranslate(v bool) { + p.translate = toBool(v) +} + +func (p *Params) SetSplitOnWord(v bool) { + p.split_on_word = toBool(v) +} + +func (p *Params) SetNoContext(v bool) { + p.no_context = toBool(v) +} + +func (p *Params) SetSingleSegment(v bool) { + p.single_segment = toBool(v) +} + +func (p *Params) SetPrintSpecial(v bool) { + p.print_special = toBool(v) +} + +func (p *Params) SetPrintProgress(v bool) { + p.print_progress = toBool(v) +} + +func (p *Params) SetPrintRealtime(v bool) { + p.print_realtime = toBool(v) +} + +func (p *Params) SetPrintTimestamps(v bool) { + p.print_timestamps = toBool(v) +} + +// Set language id +func (p *Params) SetLanguage(lang int) error { + if lang == -1 { + p.language = nil + return nil + } + str := C.whisper_lang_str(C.int(lang)) + if str == nil { + return ErrInvalidLanguage + } else { + p.language = str + } + return nil +} + +// Get language id +func (p *Params) Language() int { + if p.language == nil { + return -1 + } + return int(C.whisper_lang_id(p.language)) +} + +// Threads available +func (p *Params) Threads() int { + return int(p.n_threads) +} + +// Set number of threads to use +func (p *Params) SetThreads(threads int) { + p.n_threads = C.int(threads) +} + +// Set start offset in ms +func (p *Params) SetOffset(offset_ms int) { + p.offset_ms = C.int(offset_ms) +} + +// Set audio duration to process in ms +func (p *Params) SetDuration(duration_ms int) { + p.duration_ms = C.int(duration_ms) +} + +// Set timestamp token probability threshold (~0.01) +func (p *Params) SetTokenThreshold(t float32) { + p.thold_pt = C.float(t) +} + +// Set timestamp token sum probability threshold (~0.01) +func (p *Params) SetTokenSumThreshold(t float32) { + p.thold_ptsum = C.float(t) +} + +// Set max segment length in characters +func (p *Params) SetMaxSegmentLength(n int) { + p.max_len = C.int(n) +} + +func (p *Params) SetTokenTimestamps(b bool) { + p.token_timestamps = toBool(b) +} + +// Set max tokens per segment (0 = no limit) +func (p *Params) SetMaxTokensPerSegment(n int) { + p.max_tokens = C.int(n) +} + +// Set audio encoder context +func (p *Params) SetAudioCtx(n int) { + p.audio_ctx = C.int(n) +} + +func (p *Params) SetMaxContext(n int) { + p.n_max_text_ctx = C.int(n) +} + +func (p *Params) SetBeamSize(n int) { + p.beam_search.beam_size = C.int(n) +} + +func (p *Params) SetEntropyThold(t float32) { + p.entropy_thold = C.float(t) +} + +// Set initial prompt +func (p *Params) SetInitialPrompt(prompt string) { + p.initial_prompt = C.CString(prompt) +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func toBool(v bool) C.bool { + if v { + return C.bool(true) + } + return C.bool(false) +} + +/////////////////////////////////////////////////////////////////////////////// +// STRINGIFY + +func (p *Params) String() string { + str := "" +} diff --git a/bindings/go/pkg/whisper/consts.go b/bindings/go/pkg/whisper/consts.go new file mode 100644 index 0000000000000000000000000000000000000000..5c22dc13a3108709d091290914e5e7bf2488e5fa --- /dev/null +++ b/bindings/go/pkg/whisper/consts.go @@ -0,0 +1,28 @@ +package whisper + +import ( + "errors" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// ERRORS + +var ( + ErrUnableToLoadModel = errors.New("unable to load model") + ErrInternalAppError = errors.New("internal application error") + ErrProcessingFailed = errors.New("processing failed") + ErrUnsupportedLanguage = errors.New("unsupported language") + ErrModelNotMultilingual = errors.New("model is not multilingual") +) + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +// SampleRate is the sample rate of the audio data. +const SampleRate = whisper.SampleRate + +// SampleBits is the number of bytes per sample. +const SampleBits = whisper.SampleBits diff --git a/bindings/go/pkg/whisper/context.go b/bindings/go/pkg/whisper/context.go new file mode 100644 index 0000000000000000000000000000000000000000..dc34aa18bb87f66736b51b166c92cfaccf7caca5 --- /dev/null +++ b/bindings/go/pkg/whisper/context.go @@ -0,0 +1,331 @@ +package whisper + +import ( + "fmt" + "io" + "runtime" + "strings" + "time" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type context struct { + n int + model *model + params whisper.Params +} + +// Make sure context adheres to the interface +var _ Context = (*context)(nil) + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func newContext(model *model, params whisper.Params) (Context, error) { + context := new(context) + context.model = model + context.params = params + + // Return success + return context, nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Set the language to use for speech recognition. +func (context *context) SetLanguage(lang string) error { + if context.model.ctx == nil { + return ErrInternalAppError + } + if !context.model.IsMultilingual() { + return ErrModelNotMultilingual + } + + if lang == "auto" { + context.params.SetLanguage(-1) + } else if id := context.model.ctx.Whisper_lang_id(lang); id < 0 { + return ErrUnsupportedLanguage + } else if err := context.params.SetLanguage(id); err != nil { + return err + } + // Return success + return nil +} + +func (context *context) IsMultilingual() bool { + return context.model.IsMultilingual() +} + +// Get language +func (context *context) Language() string { + id := context.params.Language() + if id == -1 { + return "auto" + } + return whisper.Whisper_lang_str(context.params.Language()) +} + +// Set translate flag +func (context *context) SetTranslate(v bool) { + context.params.SetTranslate(v) +} + +func (context *context) SetSplitOnWord(v bool) { + context.params.SetSplitOnWord(v) +} + +// Set number of threads to use +func (context *context) SetThreads(v uint) { + context.params.SetThreads(int(v)) +} + +// Set time offset +func (context *context) SetOffset(v time.Duration) { + context.params.SetOffset(int(v.Milliseconds())) +} + +// Set duration of audio to process +func (context *context) SetDuration(v time.Duration) { + context.params.SetDuration(int(v.Milliseconds())) +} + +// Set timestamp token probability threshold (~0.01) +func (context *context) SetTokenThreshold(t float32) { + context.params.SetTokenThreshold(t) +} + +// Set timestamp token sum probability threshold (~0.01) +func (context *context) SetTokenSumThreshold(t float32) { + context.params.SetTokenSumThreshold(t) +} + +// Set max segment length in characters +func (context *context) SetMaxSegmentLength(n uint) { + context.params.SetMaxSegmentLength(int(n)) +} + +// Set token timestamps flag +func (context *context) SetTokenTimestamps(b bool) { + context.params.SetTokenTimestamps(b) +} + +// Set max tokens per segment (0 = no limit) +func (context *context) SetMaxTokensPerSegment(n uint) { + context.params.SetMaxTokensPerSegment(int(n)) +} + +// Set audio encoder context +func (context *context) SetAudioCtx(n uint) { + context.params.SetAudioCtx(int(n)) +} + +// Set maximum number of text context tokens to store +func (context *context) SetMaxContext(n int) { + context.params.SetMaxContext(n) +} + +// Set Beam Size +func (context *context) SetBeamSize(n int) { + context.params.SetBeamSize(n) +} + +// Set Entropy threshold +func (context *context) SetEntropyThold(t float32) { + context.params.SetEntropyThold(t) +} + +// Set initial prompt +func (context *context) SetInitialPrompt(prompt string) { + context.params.SetInitialPrompt(prompt) +} + +// ResetTimings resets the mode timings. Should be called before processing +func (context *context) ResetTimings() { + context.model.ctx.Whisper_reset_timings() +} + +// PrintTimings prints the model timings to stdout. +func (context *context) PrintTimings() { + context.model.ctx.Whisper_print_timings() +} + +// SystemInfo returns the system information +func (context *context) SystemInfo() string { + return fmt.Sprintf("system_info: n_threads = %d / %d | %s\n", + context.params.Threads(), + runtime.NumCPU(), + whisper.Whisper_print_system_info(), + ) +} + +// Use mel data at offset_ms to try and auto-detect the spoken language +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// Returns the probabilities of all languages. +func (context *context) WhisperLangAutoDetect(offset_ms int, n_threads int) ([]float32, error) { + langProbs, err := context.model.ctx.Whisper_lang_auto_detect(offset_ms, n_threads) + if err != nil { + return nil, err + } + return langProbs, nil +} + +// Process new sample data and return any errors +func (context *context) Process( + data []float32, + callNewSegment SegmentCallback, + callProgress ProgressCallback, +) error { + if context.model.ctx == nil { + return ErrInternalAppError + } + // If the callback is defined then we force on single_segment mode + if callNewSegment != nil { + context.params.SetSingleSegment(true) + } + + // We don't do parallel processing at the moment + processors := 0 + if processors > 1 { + if err := context.model.ctx.Whisper_full_parallel(context.params, data, processors, nil, func(new int) { + if callNewSegment != nil { + num_segments := context.model.ctx.Whisper_full_n_segments() + s0 := num_segments - new + for i := s0; i < num_segments; i++ { + callNewSegment(toSegment(context.model.ctx, i)) + } + } + }); err != nil { + return err + } + } else if err := context.model.ctx.Whisper_full(context.params, data, nil, func(new int) { + if callNewSegment != nil { + num_segments := context.model.ctx.Whisper_full_n_segments() + s0 := num_segments - new + for i := s0; i < num_segments; i++ { + callNewSegment(toSegment(context.model.ctx, i)) + } + } + }, func(progress int) { + if callProgress != nil { + callProgress(progress) + } + }); err != nil { + return err + } + + // Return success + return nil +} + +// Return the next segment of tokens +func (context *context) NextSegment() (Segment, error) { + if context.model.ctx == nil { + return Segment{}, ErrInternalAppError + } + if context.n >= context.model.ctx.Whisper_full_n_segments() { + return Segment{}, io.EOF + } + + // Populate result + result := toSegment(context.model.ctx, context.n) + + // Increment the cursor + context.n++ + + // Return success + return result, nil +} + +// Test for text tokens +func (context *context) IsText(t Token) bool { + switch { + case context.IsBEG(t): + return false + case context.IsSOT(t): + return false + case whisper.Token(t.Id) >= context.model.ctx.Whisper_token_eot(): + return false + case context.IsPREV(t): + return false + case context.IsSOLM(t): + return false + case context.IsNOT(t): + return false + default: + return true + } +} + +// Test for "begin" token +func (context *context) IsBEG(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_beg() +} + +// Test for "start of transcription" token +func (context *context) IsSOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_sot() +} + +// Test for "end of transcription" token +func (context *context) IsEOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_eot() +} + +// Test for "start of prev" token +func (context *context) IsPREV(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_prev() +} + +// Test for "start of lm" token +func (context *context) IsSOLM(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_solm() +} + +// Test for "No timestamps" token +func (context *context) IsNOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_not() +} + +// Test for token associated with a specific language +func (context *context) IsLANG(t Token, lang string) bool { + if id := context.model.ctx.Whisper_lang_id(lang); id >= 0 { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_lang(id) + } else { + return false + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func toSegment(ctx *whisper.Context, n int) Segment { + return Segment{ + Num: n, + Text: strings.TrimSpace(ctx.Whisper_full_get_segment_text(n)), + Start: time.Duration(ctx.Whisper_full_get_segment_t0(n)) * time.Millisecond * 10, + End: time.Duration(ctx.Whisper_full_get_segment_t1(n)) * time.Millisecond * 10, + Tokens: toTokens(ctx, n), + } +} + +func toTokens(ctx *whisper.Context, n int) []Token { + result := make([]Token, ctx.Whisper_full_n_tokens(n)) + for i := 0; i < len(result); i++ { + data := ctx.Whisper_full_get_token_data(n, i) + + result[i] = Token{ + Id: int(ctx.Whisper_full_get_token_id(n, i)), + Text: ctx.Whisper_full_get_token_text(n, i), + P: ctx.Whisper_full_get_token_p(n, i), + Start: time.Duration(data.T0()) * time.Millisecond * 10, + End: time.Duration(data.T1()) * time.Millisecond * 10, + } + } + return result +} diff --git a/bindings/go/pkg/whisper/context_test.go b/bindings/go/pkg/whisper/context_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c8c6016e9341b576a318b8c6523b9f6f44ea0729 --- /dev/null +++ b/bindings/go/pkg/whisper/context_test.go @@ -0,0 +1,55 @@ +package whisper_test + +import ( + "os" + "testing" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" + assert "github.com/stretchr/testify/assert" +) + +const ( + ModelPath = "../../models/ggml-tiny.bin" + SamplePath = "../../samples/jfk.wav" +) + +func Test_Whisper_000(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Load model + model, err := whisper.New(ModelPath) + assert.NoError(err) + assert.NotNil(model) + assert.NoError(model.Close()) + + t.Log("languages=", model.Languages()) +} + +func Test_Whisper_001(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Load model + model, err := whisper.New(ModelPath) + assert.NoError(err) + assert.NotNil(model) + defer model.Close() + + // Get context for decoding + ctx, err := model.NewContext() + assert.NoError(err) + assert.NotNil(ctx) + +} diff --git a/bindings/go/pkg/whisper/doc.go b/bindings/go/pkg/whisper/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..fd4f1b97250e748b75038b56c5560b32167fff5c --- /dev/null +++ b/bindings/go/pkg/whisper/doc.go @@ -0,0 +1,4 @@ +/* +This is the higher-level speech-to-text whisper.cpp API for go +*/ +package whisper diff --git a/bindings/go/pkg/whisper/interface.go b/bindings/go/pkg/whisper/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..6eb692ef6102b351fff7452dcb19dbd0b1ecfe78 --- /dev/null +++ b/bindings/go/pkg/whisper/interface.go @@ -0,0 +1,102 @@ +package whisper + +import ( + "io" + "time" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +// SegmentCallback is the callback function for processing segments in real +// time. It is called during the Process function +type SegmentCallback func(Segment) + +// ProgressCallback is the callback function for reporting progress during +// processing. It is called during the Process function +type ProgressCallback func(int) + +// Model is the interface to a whisper model. Create a new model with the +// function whisper.New(string) +type Model interface { + io.Closer + + // Return a new speech-to-text context. + NewContext() (Context, error) + + // Return true if the model is multilingual. + IsMultilingual() bool + + // Return all languages supported. + Languages() []string +} + +// Context is the speach recognition context. +type Context interface { + SetLanguage(string) error // Set the language to use for speech recognition, use "auto" for auto detect language. + SetTranslate(bool) // Set translate flag + IsMultilingual() bool // Return true if the model is multilingual. + Language() string // Get language + + SetOffset(time.Duration) // Set offset + SetDuration(time.Duration) // Set duration + SetThreads(uint) // Set number of threads to use + SetSplitOnWord(bool) // Set split on word flag + SetTokenThreshold(float32) // Set timestamp token probability threshold + SetTokenSumThreshold(float32) // Set timestamp token sum probability threshold + SetMaxSegmentLength(uint) // Set max segment length in characters + SetTokenTimestamps(bool) // Set token timestamps flag + SetMaxTokensPerSegment(uint) // Set max tokens per segment (0 = no limit) + SetAudioCtx(uint) // Set audio encoder context + SetMaxContext(n int) // Set maximum number of text context tokens to store + SetBeamSize(n int) // Set Beam Size + SetEntropyThold(t float32) // Set Entropy threshold + SetInitialPrompt(prompt string) // Set initial prompt + + // Process mono audio data and return any errors. + // If defined, newly generated segments are passed to the + // callback function during processing. + Process([]float32, SegmentCallback, ProgressCallback) error + + // After process is called, return segments until the end of the stream + // is reached, when io.EOF is returned. + NextSegment() (Segment, error) + + IsBEG(Token) bool // Test for "begin" token + IsSOT(Token) bool // Test for "start of transcription" token + IsEOT(Token) bool // Test for "end of transcription" token + IsPREV(Token) bool // Test for "start of prev" token + IsSOLM(Token) bool // Test for "start of lm" token + IsNOT(Token) bool // Test for "No timestamps" token + IsLANG(Token, string) bool // Test for token associated with a specific language + IsText(Token) bool // Test for text token + + // Timings + PrintTimings() + ResetTimings() + + SystemInfo() string +} + +// Segment is the text result of a speech recognition. +type Segment struct { + // Segment Number + Num int + + // Time beginning and end timestamps for the segment. + Start, End time.Duration + + // The text of the segment. + Text string + + // The tokens of the segment. + Tokens []Token +} + +// Token is a text or special token +type Token struct { + Id int + Text string + P float32 + Start, End time.Duration +} diff --git a/bindings/go/pkg/whisper/model.go b/bindings/go/pkg/whisper/model.go new file mode 100644 index 0000000000000000000000000000000000000000..68a150223c73b885bf7503e5f2b6dba1fe04c2b0 --- /dev/null +++ b/bindings/go/pkg/whisper/model.go @@ -0,0 +1,101 @@ +package whisper + +import ( + "fmt" + "os" + "runtime" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type model struct { + path string + ctx *whisper.Context +} + +// Make sure model adheres to the interface +var _ Model = (*model)(nil) + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func New(path string) (Model, error) { + model := new(model) + if _, err := os.Stat(path); err != nil { + return nil, err + } else if ctx := whisper.Whisper_init(path); ctx == nil { + return nil, ErrUnableToLoadModel + } else { + model.ctx = ctx + model.path = path + } + + // Return success + return model, nil +} + +func (model *model) Close() error { + if model.ctx != nil { + model.ctx.Whisper_free() + } + + // Release resources + model.ctx = nil + + // Return success + return nil +} + +/////////////////////////////////////////////////////////////////////////////// +// STRINGIFY + +func (model *model) String() string { + str := "" +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Return true if model is multilingual (language and translation options are supported) +func (model *model) IsMultilingual() bool { + return model.ctx.Whisper_is_multilingual() != 0 +} + +// Return all recognized languages. Initially it is set to auto-detect +func (model *model) Languages() []string { + result := make([]string, 0, whisper.Whisper_lang_max_id()) + for i := 0; i < whisper.Whisper_lang_max_id(); i++ { + str := whisper.Whisper_lang_str(i) + if model.ctx.Whisper_lang_id(str) >= 0 { + result = append(result, str) + } + } + return result +} + +func (model *model) NewContext() (Context, error) { + if model.ctx == nil { + return nil, ErrInternalAppError + } + + // Create new context + params := model.ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY) + params.SetTranslate(false) + params.SetPrintSpecial(false) + params.SetPrintProgress(false) + params.SetPrintRealtime(false) + params.SetPrintTimestamps(false) + params.SetThreads(runtime.NumCPU()) + params.SetNoContext(true) + + // Return new context + return newContext(model, params) +} diff --git a/bindings/go/samples/jfk.wav b/bindings/go/samples/jfk.wav new file mode 100644 index 0000000000000000000000000000000000000000..3184d372cd2f8b804d3a540c70ec50d927b335d2 Binary files /dev/null and b/bindings/go/samples/jfk.wav differ diff --git a/bindings/go/whisper.go b/bindings/go/whisper.go new file mode 100644 index 0000000000000000000000000000000000000000..39ec43b47ed7fbe0de46edd008d5fe13ed3b7d3f --- /dev/null +++ b/bindings/go/whisper.go @@ -0,0 +1,468 @@ +package whisper + +import ( + "errors" + "unsafe" +) + +/////////////////////////////////////////////////////////////////////////////// +// CGO + +/* +#cgo LDFLAGS: -lwhisper -lm -lstdc++ -fopenmp +#cgo darwin LDFLAGS: -framework Accelerate -framework Metal -framework Foundation -framework CoreGraphics +#include +#include + +extern void callNewSegment(void* user_data, int new); +extern void callProgress(void* user_data, int progress); +extern bool callEncoderBegin(void* user_data); + +// Text segment callback +// Called on every newly generated text segment +// Use the whisper_full_...() functions to obtain the text segments +static void whisper_new_segment_cb(struct whisper_context* ctx, struct whisper_state* state, int n_new, void* user_data) { + if(user_data != NULL && ctx != NULL) { + callNewSegment(user_data, n_new); + } +} + +// Progress callback +// Called on every newly generated text segment +// Use the whisper_full_...() functions to obtain the text segments +static void whisper_progress_cb(struct whisper_context* ctx, struct whisper_state* state, int progress, void* user_data) { + if(user_data != NULL && ctx != NULL) { + callProgress(user_data, progress); + } +} + +// Encoder begin callback +// If not NULL, called before the encoder starts +// If it returns false, the computation is aborted +static bool whisper_encoder_begin_cb(struct whisper_context* ctx, struct whisper_state* state, void* user_data) { + if(user_data != NULL && ctx != NULL) { + return callEncoderBegin(user_data); + } + return false; +} + +// Get default parameters and set callbacks +static struct whisper_full_params whisper_full_default_params_cb(struct whisper_context* ctx, enum whisper_sampling_strategy strategy) { + struct whisper_full_params params = whisper_full_default_params(strategy); + params.new_segment_callback = whisper_new_segment_cb; + params.new_segment_callback_user_data = (void*)(ctx); + params.encoder_begin_callback = whisper_encoder_begin_cb; + params.encoder_begin_callback_user_data = (void*)(ctx); + params.progress_callback = whisper_progress_cb; + params.progress_callback_user_data = (void*)(ctx); + return params; +} +*/ +import "C" + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type ( + Context C.struct_whisper_context + Token C.whisper_token + TokenData C.struct_whisper_token_data + SamplingStrategy C.enum_whisper_sampling_strategy + Params C.struct_whisper_full_params +) + +/////////////////////////////////////////////////////////////////////////////// +// GLOBALS + +const ( + SAMPLING_GREEDY SamplingStrategy = C.WHISPER_SAMPLING_GREEDY + SAMPLING_BEAM_SEARCH SamplingStrategy = C.WHISPER_SAMPLING_BEAM_SEARCH +) + +const ( + SampleRate = C.WHISPER_SAMPLE_RATE // Expected sample rate, samples per second + SampleBits = uint16(unsafe.Sizeof(C.float(0))) * 8 // Sample size in bits + NumFFT = C.WHISPER_N_FFT + HopLength = C.WHISPER_HOP_LENGTH + ChunkSize = C.WHISPER_CHUNK_SIZE +) + +var ( + ErrTokenizerFailed = errors.New("whisper_tokenize failed") + ErrAutoDetectFailed = errors.New("whisper_lang_auto_detect failed") + ErrConversionFailed = errors.New("whisper_convert failed") + ErrInvalidLanguage = errors.New("invalid language") +) + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Allocates all memory needed for the model and loads the model from the given file. +// Returns NULL on failure. +func Whisper_init(path string) *Context { + cPath := C.CString(path) + defer C.free(unsafe.Pointer(cPath)) + if ctx := C.whisper_init_from_file_with_params(cPath, C.whisper_context_default_params()); ctx != nil { + return (*Context)(ctx) + } else { + return nil + } +} + +// Frees all memory allocated by the model. +func (ctx *Context) Whisper_free() { + C.whisper_free((*C.struct_whisper_context)(ctx)) +} + +// Convert RAW PCM audio to log mel spectrogram. +// The resulting spectrogram is stored inside the provided whisper context. +func (ctx *Context) Whisper_pcm_to_mel(data []float32, threads int) error { + if C.whisper_pcm_to_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// This can be used to set a custom log mel spectrogram inside the provided whisper context. +// Use this instead of whisper_pcm_to_mel() if you want to provide your own log mel spectrogram. +// n_mel must be 80 +func (ctx *Context) Whisper_set_mel(data []float32, n_mel int) error { + if C.whisper_set_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(n_mel)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Run the Whisper encoder on the log mel spectrogram stored inside the provided whisper context. +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// offset can be used to specify the offset of the first frame in the spectrogram. +func (ctx *Context) Whisper_encode(offset, threads int) error { + if C.whisper_encode((*C.struct_whisper_context)(ctx), C.int(offset), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Run the Whisper decoder to obtain the logits and probabilities for the next token. +// Make sure to call whisper_encode() first. +// tokens + n_tokens is the provided context for the decoder. +// n_past is the number of tokens to use from previous decoder calls. +func (ctx *Context) Whisper_decode(tokens []Token, past, threads int) error { + if C.whisper_decode((*C.struct_whisper_context)(ctx), (*C.whisper_token)(&tokens[0]), C.int(len(tokens)), C.int(past), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Convert the provided text into tokens. The tokens pointer must be large enough to hold the resulting tokens. +// Returns the number of tokens on success +func (ctx *Context) Whisper_tokenize(text string, tokens []Token) (int, error) { + cText := C.CString(text) + defer C.free(unsafe.Pointer(cText)) + if n := C.whisper_tokenize((*C.struct_whisper_context)(ctx), cText, (*C.whisper_token)(&tokens[0]), C.int(len(tokens))); n >= 0 { + return int(n), nil + } else { + return 0, ErrTokenizerFailed + } +} + +// Return the id of the specified language, returns -1 if not found +// Examples: +// +// "de" -> 2 +// "german" -> 2 +func (ctx *Context) Whisper_lang_id(lang string) int { + return int(C.whisper_lang_id(C.CString(lang))) +} + +// Largest language id (i.e. number of available languages - 1) +func Whisper_lang_max_id() int { + return int(C.whisper_lang_max_id()) +} + +// Return the short string of the specified language id (e.g. 2 -> "de"), +// returns empty string if not found +func Whisper_lang_str(id int) string { + return C.GoString(C.whisper_lang_str(C.int(id))) +} + +// Use mel data at offset_ms to try and auto-detect the spoken language +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// Returns the probabilities of all languages. +// ref: https://github.com/openai/whisper/blob/main/whisper/decoding.py#L18-L69 +func (ctx *Context) Whisper_lang_auto_detect(offset_ms, n_threads int) ([]float32, error) { + probs := make([]float32, Whisper_lang_max_id()+1) + if n := int(C.whisper_lang_auto_detect((*C.struct_whisper_context)(ctx), C.int(offset_ms), C.int(n_threads), (*C.float)(&probs[0]))); n < 0 { + return nil, ErrAutoDetectFailed + } else { + return probs, nil + } +} + +func (ctx *Context) Whisper_n_len() int { + return int(C.whisper_n_len((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_vocab() int { + return int(C.whisper_n_vocab((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_text_ctx() int { + return int(C.whisper_n_text_ctx((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_audio_ctx() int { + return int(C.whisper_n_audio_ctx((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_is_multilingual() int { + return int(C.whisper_is_multilingual((*C.struct_whisper_context)(ctx))) +} + +// The probabilities for the next token +//func (ctx *Whisper_context) Whisper_get_probs() []float32 { +// return (*[1 << 30]float32)(unsafe.Pointer(C.whisper_get_probs((*C.struct_whisper_context)(ctx))))[:ctx.Whisper_n_vocab()] +//} + +// Token Id -> String. Uses the vocabulary in the provided context +func (ctx *Context) Whisper_token_to_str(token Token) string { + return C.GoString(C.whisper_token_to_str((*C.struct_whisper_context)(ctx), C.whisper_token(token))) +} + +// Special tokens +func (ctx *Context) Whisper_token_eot() Token { + return Token(C.whisper_token_eot((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_sot() Token { + return Token(C.whisper_token_sot((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_prev() Token { + return Token(C.whisper_token_prev((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_solm() Token { + return Token(C.whisper_token_solm((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_not() Token { + return Token(C.whisper_token_not((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_beg() Token { + return Token(C.whisper_token_beg((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_lang(lang_id int) Token { + return Token(C.whisper_token_lang((*C.struct_whisper_context)(ctx), C.int(lang_id))) +} + +// Task tokens +func (ctx *Context) Whisper_token_translate() Token { + return Token(C.whisper_token_translate((*C.struct_whisper_context)(ctx))) +} + +// Task tokens +func (ctx *Context) Whisper_token_transcribe() Token { + return Token(C.whisper_token_transcribe((*C.struct_whisper_context)(ctx))) +} + +// Performance information +func (ctx *Context) Whisper_print_timings() { + C.whisper_print_timings((*C.struct_whisper_context)(ctx)) +} + +// Performance information +func (ctx *Context) Whisper_reset_timings() { + C.whisper_reset_timings((*C.struct_whisper_context)(ctx)) +} + +// Print system information +func Whisper_print_system_info() string { + return C.GoString(C.whisper_print_system_info()) +} + +// Return default parameters for a strategy +func (ctx *Context) Whisper_full_default_params(strategy SamplingStrategy) Params { + // Get default parameters + return Params(C.whisper_full_default_params_cb((*C.struct_whisper_context)(ctx), C.enum_whisper_sampling_strategy(strategy))) +} + +// Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text +// Uses the specified decoding strategy to obtain the text. +func (ctx *Context) Whisper_full( + params Params, + samples []float32, + encoderBeginCallback func() bool, + newSegmentCallback func(int), + progressCallback func(int), +) error { + registerEncoderBeginCallback(ctx, encoderBeginCallback) + registerNewSegmentCallback(ctx, newSegmentCallback) + registerProgressCallback(ctx, progressCallback) + defer registerEncoderBeginCallback(ctx, nil) + defer registerNewSegmentCallback(ctx, nil) + defer registerProgressCallback(ctx, nil) + if C.whisper_full((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples))) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Split the input audio in chunks and process each chunk separately using whisper_full() +// It seems this approach can offer some speedup in some cases. +// However, the transcription accuracy can be worse at the beginning and end of each chunk. +func (ctx *Context) Whisper_full_parallel(params Params, samples []float32, processors int, encoderBeginCallback func() bool, newSegmentCallback func(int)) error { + registerEncoderBeginCallback(ctx, encoderBeginCallback) + registerNewSegmentCallback(ctx, newSegmentCallback) + defer registerEncoderBeginCallback(ctx, nil) + defer registerNewSegmentCallback(ctx, nil) + + if C.whisper_full_parallel((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples)), C.int(processors)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Return the id of the autodetected language, returns -1 if not found +// Added to whisper.cpp in +// https://github.com/ggerganov/whisper.cpp/commit/a1c1583cc7cd8b75222857afc936f0638c5683d6 +// +// Examples: +// +// "de" -> 2 +// "german" -> 2 +func (ctx *Context) Whisper_full_lang_id() int { + return int(C.whisper_full_lang_id((*C.struct_whisper_context)(ctx))) +} + +// Number of generated text segments. +// A segment can be a few words, a sentence, or even a paragraph. +func (ctx *Context) Whisper_full_n_segments() int { + return int(C.whisper_full_n_segments((*C.struct_whisper_context)(ctx))) +} + +// Get the start and end time of the specified segment. +func (ctx *Context) Whisper_full_get_segment_t0(segment int) int64 { + return int64(C.whisper_full_get_segment_t0((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the start and end time of the specified segment. +func (ctx *Context) Whisper_full_get_segment_t1(segment int) int64 { + return int64(C.whisper_full_get_segment_t1((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the text of the specified segment. +func (ctx *Context) Whisper_full_get_segment_text(segment int) string { + return C.GoString(C.whisper_full_get_segment_text((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get number of tokens in the specified segment. +func (ctx *Context) Whisper_full_n_tokens(segment int) int { + return int(C.whisper_full_n_tokens((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the token text of the specified token index in the specified segment. +func (ctx *Context) Whisper_full_get_token_text(segment int, token int) string { + return C.GoString(C.whisper_full_get_token_text((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get the token of the specified token index in the specified segment. +func (ctx *Context) Whisper_full_get_token_id(segment int, token int) Token { + return Token(C.whisper_full_get_token_id((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get token data for the specified token in the specified segment. +// This contains probabilities, timestamps, etc. +func (ctx *Context) Whisper_full_get_token_data(segment int, token int) TokenData { + return TokenData(C.whisper_full_get_token_data((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get the probability of the specified token in the specified segment. +func (ctx *Context) Whisper_full_get_token_p(segment int, token int) float32 { + return float32(C.whisper_full_get_token_p((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +/////////////////////////////////////////////////////////////////////////////// +// CALLBACKS + +var ( + cbNewSegment = make(map[unsafe.Pointer]func(int)) + cbProgress = make(map[unsafe.Pointer]func(int)) + cbEncoderBegin = make(map[unsafe.Pointer]func() bool) +) + +func registerNewSegmentCallback(ctx *Context, fn func(int)) { + if fn == nil { + delete(cbNewSegment, unsafe.Pointer(ctx)) + } else { + cbNewSegment[unsafe.Pointer(ctx)] = fn + } +} + +func registerProgressCallback(ctx *Context, fn func(int)) { + if fn == nil { + delete(cbProgress, unsafe.Pointer(ctx)) + } else { + cbProgress[unsafe.Pointer(ctx)] = fn + } +} + +func registerEncoderBeginCallback(ctx *Context, fn func() bool) { + if fn == nil { + delete(cbEncoderBegin, unsafe.Pointer(ctx)) + } else { + cbEncoderBegin[unsafe.Pointer(ctx)] = fn + } +} + +//export callNewSegment +func callNewSegment(user_data unsafe.Pointer, new C.int) { + if fn, ok := cbNewSegment[user_data]; ok { + fn(int(new)) + } +} + +//export callProgress +func callProgress(user_data unsafe.Pointer, progress C.int) { + if fn, ok := cbProgress[user_data]; ok { + fn(int(progress)) + } +} + +//export callEncoderBegin +func callEncoderBegin(user_data unsafe.Pointer) C.bool { + if fn, ok := cbEncoderBegin[user_data]; ok { + if fn() { + return C.bool(true) + } else { + return C.bool(false) + } + } + return true +} + +func (t TokenData) T0() int64 { + return int64(t.t0) +} + +func (t TokenData) T1() int64 { + return int64(t.t1) +} + +func (t TokenData) Id() Token { + return Token(t.id) +} diff --git a/bindings/go/whisper_test.go b/bindings/go/whisper_test.go new file mode 100644 index 0000000000000000000000000000000000000000..40648ffa8d4e59d026820474ef2c17ffb577aed0 --- /dev/null +++ b/bindings/go/whisper_test.go @@ -0,0 +1,113 @@ +package whisper_test + +import ( + "os" + "runtime" + "testing" + "time" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go" + wav "github.com/go-audio/wav" + assert "github.com/stretchr/testify/assert" +) + +const ( + ModelPath = "models/ggml-small.en.bin" + SamplePath = "samples/jfk.wav" +) + +func Test_Whisper_000(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + ctx.Whisper_free() +} + +func Test_Whisper_001(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Open samples + fh, err := os.Open(SamplePath) + assert.NoError(err) + defer fh.Close() + + // Read samples + d := wav.NewDecoder(fh) + buf, err := d.FullPCMBuffer() + assert.NoError(err) + + // Run whisper + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + defer ctx.Whisper_free() + params := ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY) + data := buf.AsFloat32Buffer().Data + err = ctx.Whisper_full(params, data, nil, nil, nil) + assert.NoError(err) + + // Print out tokens + num_segments := ctx.Whisper_full_n_segments() + assert.GreaterOrEqual(num_segments, 1) + for i := 0; i < num_segments; i++ { + str := ctx.Whisper_full_get_segment_text(i) + assert.NotEmpty(str) + t0 := time.Duration(ctx.Whisper_full_get_segment_t0(i)) * time.Millisecond + t1 := time.Duration(ctx.Whisper_full_get_segment_t1(i)) * time.Millisecond + t.Logf("[%6s->%-6s] %q", t0, t1, str) + } +} + +func Test_Whisper_002(t *testing.T) { + assert := assert.New(t) + for i := 0; i < whisper.Whisper_lang_max_id(); i++ { + str := whisper.Whisper_lang_str(i) + assert.NotEmpty(str) + t.Log(str) + } +} + +func Test_Whisper_003(t *testing.T) { + threads := runtime.NumCPU() + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Open samples + fh, err := os.Open(SamplePath) + assert.NoError(err) + defer fh.Close() + + // Read samples + d := wav.NewDecoder(fh) + buf, err := d.FullPCMBuffer() + assert.NoError(err) + + // Make the model + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + defer ctx.Whisper_free() + + // Get MEL + assert.NoError(ctx.Whisper_pcm_to_mel(buf.AsFloat32Buffer().Data, threads)) + + // Get Languages + languages, err := ctx.Whisper_lang_auto_detect(0, threads) + assert.NoError(err) + for i, p := range languages { + t.Logf("%s: %f", whisper.Whisper_lang_str(i), p) + } +} diff --git a/bindings/java/.idea/uiDesigner.xml b/bindings/java/.idea/uiDesigner.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d50cd4da8dae4a3ad24b687d22e92eb6b56a514 --- /dev/null +++ b/bindings/java/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bindings/java/README.md b/bindings/java/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5255612e398a329145633a312f82cac78ba952d2 --- /dev/null +++ b/bindings/java/README.md @@ -0,0 +1,71 @@ +# Java JNI bindings for Whisper + +This package provides Java JNI bindings for whisper.cpp. They have been tested on: + + * Darwin (OS X) 12.6 on x64_64 + * Ubuntu on x86_64 + * Windows on x86_64 + +The "low level" bindings are in `WhisperCppJnaLibrary`. The most simple usage is as follows: + +JNA will attempt to load the `whispercpp` shared library from: + +- jna.library.path +- jna.platform.library +- ~/Library/Frameworks +- /Library/Frameworks +- /System/Library/Frameworks +- classpath + +```java +import io.github.ggerganov.whispercpp.WhisperCpp; + +public class Example { + + public static void main(String[] args) { + WhisperCpp whisper = new WhisperCpp(); + // By default, models are loaded from ~/.cache/whisper/ and are usually named "ggml-${name}.bin" + // or you can provide the absolute path to the model file. + long context = whisper.initContext("base.en"); + try { + var whisperParams = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + // custom configuration if required + whisperParams.temperature_inc = 0f; + + var samples = readAudio(); // divide each value by 32767.0f + whisper.fullTranscribe(whisperParams, samples); + + int segmentCount = whisper.getTextSegmentCount(context); + for (int i = 0; i < segmentCount; i++) { + String text = whisper.getTextSegment(context, i); + System.out.println(segment.getText()); + } + } finally { + whisper.freeContext(context); + } + } +} +``` + +## Building & Testing + +In order to build, you need to have the JDK 8 or higher installed. Run the tests with: + +```bash +git clone https://github.com/ggerganov/whisper.cpp.git +cd whisper.cpp/bindings/java + +./gradlew build +``` + +You need to have the `whisper` library in your [JNA library path](https://java-native-access.github.io/jna/4.2.1/com/sun/jna/NativeLibrary.html). On Windows the dll is included in the jar and you can update it: + +```bash +copy /y ..\..\build\bin\Release\whisper.dll build\generated\resources\main\win32-x86-64\whisper.dll +``` + + +## License + +The license for the Go bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details. + diff --git a/bindings/java/build.gradle b/bindings/java/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..75f3a9cd9018d684966bdf7b68cb6905935e3731 --- /dev/null +++ b/bindings/java/build.gradle @@ -0,0 +1,133 @@ +plugins { + id 'java' + id 'java-library' + id 'maven-publish' + id 'signing' +} + +archivesBaseName = 'whispercpp' +group = 'io.github.ggerganov' +version = '1.4.0' + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +sourceSets { + main { + resources { + srcDirs = ['src/main/resources', 'build/generated/resources/main'] + } + } + test { + runtimeClasspath += files('build/generated/resources/main') + } +} + +tasks.register('copyLibwhisperDynlib', Copy) { + from '../../build' + include 'libwhisper.dynlib' + into 'build/generated/resources/main/darwin' +} + +tasks.register('copyLibwhisperSo', Copy) { + from '../../build' + include 'libwhisper.so' + into 'build/generated/resources/main/linux-x86-64' +} + +tasks.register('copyWhisperDll', Copy) { + from '../../build/Release' + include 'whisper.dll' + into 'build/generated/resources/main/windows-x86-64' +} + +tasks.register('copyLibs') { + dependsOn copyLibwhisperDynlib, copyLibwhisperSo, copyWhisperDll +} + +test { + systemProperty 'jna.library.path', project.file('build/generated/resources/main').absolutePath +} + +java { + withSourcesJar() + withJavadocJar() +} + +jar { + exclude '**/whisper_java.exp', '**/whisper_java.lib' +} + +javadoc { + options.addStringOption('Xdoclint:none', '-quiet') +} + +tasks.withType(Test) { + useJUnitPlatform() +} + +dependencies { + implementation "net.java.dev.jna:jna:5.13.0" + testImplementation "org.junit.jupiter:junit-jupiter:5.9.2" + testImplementation "org.assertj:assertj-core:3.24.2" +} + +repositories { + mavenCentral() +} + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'whispercpp' + from components.java + pom { + name = 'whispercpp' + description = "Java JNA bindings for OpenAI's Whisper model, implemented in C/C++" + url = 'https://github.com/ggerganov/whisper.cpp' + licenses { + license { + name = 'MIT licence' + url = 'https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/LICENSE' + } + } + developers { + developer { + id = 'ggerganov' + name = 'Georgi Gerganov' + email = 'ggerganov@gmail.com' + } + developer { + id = 'nalbion' + name = 'Nicholas Albion' + email = 'nalbion@yahoo.com' + } + } + scm { + connection = 'scm:git:git://github.com/ggerganov/whisper.cpp.git' + url = 'https://github.com/ggerganov/whisper.cpp' + } + } + } + } + + repositories { + maven { + def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/' + def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' + url = version.endsWith('-SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } + } + } +} + +signing { + def signingKey = System.getenv("PGP_SECRET") + def signingPassword = System.getenv("PGP_PASSPHRASE") + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mavenJava +} diff --git a/bindings/java/gradle.properties b/bindings/java/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..3ea68c2842a12cfe33f8048cc4155bd6de008fdd --- /dev/null +++ b/bindings/java/gradle.properties @@ -0,0 +1,6 @@ +org.gradle.jvmargs=-Xms256m -Xmx1024m +system.include.dir=/usr/include +#system.local.include.dir=../../include +system.local.include.dir=./build/generated/sources/headers/java/main +jni.include.dir=/usr/lib/jvm/java-8-openjdk-amd64/include/ +jni.lib.dir=/usr/lib/jvm/java-8-openjdk-amd64/lib/ diff --git a/bindings/java/gradle/wrapper/gradle-wrapper.jar b/bindings/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a Binary files /dev/null and b/bindings/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/bindings/java/gradle/wrapper/gradle-wrapper.properties b/bindings/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..0c85a1f751970042d58a819dfce15dc9500c59d8 --- /dev/null +++ b/bindings/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/bindings/java/gradlew b/bindings/java/gradlew new file mode 100644 index 0000000000000000000000000000000000000000..79a61d421cc4e272926b1d590728d0bbfc224b0d --- /dev/null +++ b/bindings/java/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/bindings/java/gradlew.bat b/bindings/java/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..6689b85beecde676054c39c2408085f41e6be6dc --- /dev/null +++ b/bindings/java/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/bindings/java/settings.gradle b/bindings/java/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..dbc6f386c86f4285ac3f533bab09dc7a1d9c0ffe --- /dev/null +++ b/bindings/java/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "whispercpp" diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java new file mode 100644 index 0000000000000000000000000000000000000000..258a9c4c47c59b08bcd1aac0a70c8383b1ebb236 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2a4b6e54227c7d3811effefb31eeb80d1c4c744a512f39392820b9789e63f68 +size 1338 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java new file mode 100644 index 0000000000000000000000000000000000000000..a6c95fe8ef3c64475f7842f6d7a74aad869aa7ca --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31778fc7ff95e421c9202ff97b69c63d5c04e32aba5501b3a4a5e6f7bf79d475 +size 7464 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java new file mode 100644 index 0000000000000000000000000000000000000000..07eacc0ded27e44d4ba847901126ef7820d14f15 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d71c02f6f2f7bc3744a343b3332e45ff3f706b6ceab28f92796591855b6faf4 +size 15757 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java new file mode 100644 index 0000000000000000000000000000000000000000..115017acb3cc62f002a66d8b47088f8ac8aca7f9 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:464f24bac4a9be6da6994da7518a0eeae75da74240eb0af7e4be7548bd014410 +size 834 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..56f7d3bdbec5b275ce7a0504002b8fdf6ad36280 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae69f5ff18b0281c7f0ae5ce6dfb4312471f234f0f9557e3b8ed635cbf65a304 +size 801 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..32a2696dcf0895156c73a2ec1de48037617edff7 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1af80cc5f459e9ff609e991e528428c97fc4c50fe72d54c18ca8a2da60564ed +size 879 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..28e4e834ec1e9be145a438c69797a34fd5509c47 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a64648db54d620d47f3d79a0bee1e438d34225f951ac5535e98a55f622af280 +size 811 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..a5ace6d440ed6ae2d0abfc9f7dedf4314c13780e --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cee2197cfcae916c469e074652073ba12f86b5a61a55239de79d3eef90045c5 +size 667 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java new file mode 100644 index 0000000000000000000000000000000000000000..b275a10947752da93525971aa44fce306fee9725 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3b2dbc7518e5b6afe7852f6c2540977ece0ee5e0e5ae3a60a9564c82a6672b6 +size 78 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java new file mode 100644 index 0000000000000000000000000000000000000000..38133ef82edcfa340bc2e4fe134b1da736ceed05 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa6512299dc751982714ab643bebdfcde0ea2fde724b5f1dc8f99a7dfd750b6e +size 437 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java new file mode 100644 index 0000000000000000000000000000000000000000..5778d1f6059e141e396c02c2af9c3f2a069891bf --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95d6db207939136fa9c0a69ba7e3cbc75f02c9b722995bc8fab63ef54c45257e +size 183 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java new file mode 100644 index 0000000000000000000000000000000000000000..b2b884490d33706df0bd972258570b58cc6003a8 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4daef0b2e7c487beaf80c1ec1ba186bbde52be7775b40e1b6a817f041edd3a09 +size 1208 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..0db22e9160e5de34e422559166cb6f7123b5eea4 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f037f4992f2cce103e55514074118b166191eb86fea4c53ed385047b84cbbec +size 1605 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java new file mode 100644 index 0000000000000000000000000000000000000000..9e40b368137717cf50370c68091ca35c632a57d0 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dab666c8e95084bb2789c9c7ba9134facea745635224e20b10e1025e424b7f20 +size 81 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java new file mode 100644 index 0000000000000000000000000000000000000000..311974a90fcb60f7448cf17547a8a64ce585eb8c --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd90b519f461299909158a88b11a6df820f38721b7f7e1c166437cff07dca044 +size 1194 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java new file mode 100644 index 0000000000000000000000000000000000000000..49ea68d5fa688bc4d58e110bd7c766f94108f350 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a69870868740f48b5e4af644f248718e2be33e6ef847fcaa3676872c12d4288 +size 586 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java new file mode 100644 index 0000000000000000000000000000000000000000..1592a90d7e3c7e0641616507fe6ced3b3cecb2e5 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c8d7f7dbc4d4bf392b10a8e35dc06db116b0dfcbb297439925ec352629b21c1 +size 676 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java new file mode 100644 index 0000000000000000000000000000000000000000..13747618488ab8504ecbc1e79e9ea047b36eab60 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a965197895bac8cdc4dfd3e827ad0efdb3ee7fcbf2fe1cdea48c23db9b6adbba +size 476 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java new file mode 100644 index 0000000000000000000000000000000000000000..90e782ab0cb73d500bac5705aeb75dc038581aaf --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7f27687a09d9bc9467b1ce2186983edd3eaff73939a441c73f7ad96a22a5572 +size 813 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java new file mode 100644 index 0000000000000000000000000000000000000000..b5ae69d5741d12289263238368e29ddbbf208fc4 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2530d1e498926ca2ff8c8fc96ae183559a2e1a56a82b9de9accbdbddadb69306 +size 167 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java new file mode 100644 index 0000000000000000000000000000000000000000..aa524b0ea996eae456532d3c018afd4540a7bc97 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28201b7eb836bbe7b8aeba5d4f9c3561fe0caddbc00da0657c4f7f31e8aef506 +size 11356 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java new file mode 100644 index 0000000000000000000000000000000000000000..d93657842ce3211906de3e474444c42051d29333 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b930cea38bf71c5350c7cc4ba8c4a2ff4e5ae84457385addd9a444f6c7fa2f9 +size 406 diff --git a/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..f890608ac252789bdb3592d3cebdb471bb64ff29 --- /dev/null +++ b/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2217ebc7f82e809e17ace867c25175deab1edb31eb776f60dba7129e8b400b28 +size 292 diff --git a/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java b/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java new file mode 100644 index 0000000000000000000000000000000000000000..034726ad29c972d907f3fe6f7a5c9ece42cf1a6f --- /dev/null +++ b/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java @@ -0,0 +1,144 @@ +package io.github.ggerganov.whispercpp; + +import static org.junit.jupiter.api.Assertions.*; + +import io.github.ggerganov.whispercpp.bean.WhisperSegment; +import io.github.ggerganov.whispercpp.params.CBool; +import io.github.ggerganov.whispercpp.params.WhisperFullParams; +import io.github.ggerganov.whispercpp.params.WhisperSamplingStrategy; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.List; + +class WhisperCppTest { + private static WhisperCpp whisper = new WhisperCpp(); + private static boolean modelInitialised = false; + + @BeforeAll + static void init() throws FileNotFoundException { + // By default, models are loaded from ~/.cache/whisper/ and are usually named "ggml-${name}.bin" + // or you can provide the absolute path to the model file. + //String modelName = "../../models/ggml-tiny.bin"; + String modelName = "../../models/ggml-tiny.en.bin"; + try { + whisper.initContext(modelName); + //whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + //whisper.getJavaDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + modelInitialised = true; + } catch (FileNotFoundException ex) { + System.out.println("Model " + modelName + " not found"); + } + } + + @Test + void testGetDefaultFullParams_BeamSearch() { + // When + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + + // Then + assertEquals(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH.ordinal(), params.strategy); + assertNotEquals(0, params.n_threads); + assertEquals(16384, params.n_max_text_ctx); + assertFalse(params.translate); + assertEquals(0.01f, params.thold_pt); + assertEquals(5, params.beam_search.beam_size); + assertEquals(-1.0f, params.beam_search.patience); + } + + @Test + void testGetDefaultFullParams_Greedy() { + // When + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + + // Then + assertEquals(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY.ordinal(), params.strategy); + assertNotEquals(0, params.n_threads); + assertEquals(16384, params.n_max_text_ctx); + assertEquals(5, params.greedy.best_of); + } + + @Test + void testFullTranscribe() throws Exception { + if (!modelInitialised) { + System.out.println("Model not initialised, skipping test"); + return; + } + + // Given + File file = new File(System.getProperty("user.dir"), "../../samples/jfk.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); + + byte[] b = new byte[audioInputStream.available()]; + float[] floats = new float[b.length / 2]; + + //WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + params.setProgressCallback((ctx, state, progress, user_data) -> System.out.println("progress: " + progress)); + params.print_progress = CBool.FALSE; + //params.initial_prompt = "and so my fellow Americans um, like"; + + + try { + audioInputStream.read(b); + + for (int i = 0, j = 0; i < b.length; i += 2, j++) { + int intSample = (int) (b[i + 1]) << 8 | (int) (b[i]) & 0xFF; + floats[j] = intSample / 32767.0f; + } + + // When + String result = whisper.fullTranscribe(params, floats); + + // Then + System.err.println(result); + assertEquals("And so my fellow Americans ask not what your country can do for you " + + "ask what you can do for your country.", + result.replace(",", "")); + } finally { + audioInputStream.close(); + } + } + + @Test + void testFullTranscribeWithTime() throws Exception { + if (!modelInitialised) { + System.out.println("Model not initialised, skipping test"); + return; + } + + // Given + File file = new File(System.getProperty("user.dir"), "../../samples/jfk.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); + + byte[] b = new byte[audioInputStream.available()]; + float[] floats = new float[b.length / 2]; + + //WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + params.setProgressCallback((ctx, state, progress, user_data) -> System.out.println("progress: " + progress)); + params.print_progress = CBool.FALSE; + //params.initial_prompt = "and so my fellow Americans um, like"; + + try { + audioInputStream.read(b); + + for (int i = 0, j = 0; i < b.length; i += 2, j++) { + int intSample = (int) (b[i + 1]) << 8 | (int) (b[i]) & 0xFF; + floats[j] = intSample / 32767.0f; + } + + List segments = whisper.fullTranscribeWithTime(params, floats); + assertTrue(segments.size() > 0, "The size of segments should be greater than 0"); + for (WhisperSegment segment : segments) { + System.out.println(segment); + } + } finally { + audioInputStream.close(); + } + } + +} diff --git a/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java b/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..07a340c13bec42eddf108948e72ee2aec67a960a --- /dev/null +++ b/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java @@ -0,0 +1,17 @@ +package io.github.ggerganov.whispercpp; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class WhisperJnaLibraryTest { + + @Test + void testWhisperPrint_system_info() { + String systemInfo = WhisperCppJnaLibrary.instance.whisper_print_system_info(); + // eg: "AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 + // | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | COREML = 0 | " + System.out.println("System info: " + systemInfo); + assertTrue(systemInfo.length() > 10); + } +} diff --git a/bindings/javascript/.gitignore b/bindings/javascript/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..17b4c53a2aa14dc3d144ace819227f8d9637c685 --- /dev/null +++ b/bindings/javascript/.gitignore @@ -0,0 +1 @@ +publish.log diff --git a/bindings/javascript/CMakeLists.txt b/bindings/javascript/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b5af79a32fdd6decd221f7d0238276052e2b5d3 --- /dev/null +++ b/bindings/javascript/CMakeLists.txt @@ -0,0 +1,41 @@ +set(TARGET libwhisper) + +add_executable(${TARGET} + emscripten.cpp + ) + +target_link_libraries(${TARGET} PRIVATE + whisper + ) + +unset(EXTRA_FLAGS) + +if (WHISPER_WASM_SINGLE_FILE) + set(EXTRA_FLAGS "-s SINGLE_FILE=1") + message(STATUS "Embedding WASM inside whisper.js") + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libwhisper.js + ${CMAKE_CURRENT_SOURCE_DIR}/whisper.js + ) + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libwhisper.worker.js + ${CMAKE_CURRENT_SOURCE_DIR}/libwhisper.worker.js + ) +endif() + +set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ + --bind \ + -s MODULARIZE=1 \ + -s EXPORT_NAME=\"'whisper_factory'\" \ + -s FORCE_FILESYSTEM=1 \ + -s USE_PTHREADS=1 \ + -s PTHREAD_POOL_SIZE=8 \ + -s ALLOW_MEMORY_GROWTH=1 \ + ${EXTRA_FLAGS} \ + ") diff --git a/bindings/javascript/README.md b/bindings/javascript/README.md new file mode 100644 index 0000000000000000000000000000000000000000..87f3480574c43babb895a2a38fb559182e4f5153 --- /dev/null +++ b/bindings/javascript/README.md @@ -0,0 +1,78 @@ +# whisper.cpp + +Node.js package for Whisper speech recognition + +Package: https://www.npmjs.com/package/whisper.cpp + +## Details + +The performance is comparable to when running `whisper.cpp` in the browser via WASM. + +The API is currently very rudimentary: [bindings/javascript/emscripten.cpp](/bindings/javascript/emscripten.cpp) + +For sample usage check [tests/test-whisper.js](/tests/test-whisper.js) + +## Package building + test + +```bash +# load emscripten +source /path/to/emsdk/emsdk_env.sh + +# clone repo +git clone https://github.com/ggerganov/whisper.cpp +cd whisper.cpp + +# grab base.en model +./models/download-ggml-model.sh base.en + +# prepare PCM sample for testing +ffmpeg -i samples/jfk.wav -f f32le -acodec pcm_f32le samples/jfk.pcmf32 + +# build +mkdir build-em && cd build-em +emcmake cmake .. && make -j + +# run test +node --experimental-wasm-threads --experimental-wasm-simd ../tests/test-whisper.js + +# publish npm package +make publish-npm +``` + +## Sample run + +```text +$ node --experimental-wasm-threads --experimental-wasm-simd ../tests/test-whisper.js + +whisper_model_load: loading model from 'whisper.bin' +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 512 +whisper_model_load: n_audio_head = 8 +whisper_model_load: n_audio_layer = 6 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 512 +whisper_model_load: n_text_head = 8 +whisper_model_load: n_text_layer = 6 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 2 +whisper_model_load: adding 1607 extra tokens +whisper_model_load: mem_required = 506.00 MB +whisper_model_load: ggml ctx size = 140.60 MB +whisper_model_load: memory size = 22.83 MB +whisper_model_load: model size = 140.54 MB + +system_info: n_threads = 8 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | NEON = 0 | F16C = 0 | FP16_VA = 0 | WASM_SIMD = 1 | BLAS = 0 | + +operator(): processing 176000 samples, 11.0 sec, 8 threads, 1 processors, lang = en, task = transcribe ... + +[00:00:00.000 --> 00:00:11.000] And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country. + +whisper_print_timings: load time = 162.37 ms +whisper_print_timings: mel time = 183.70 ms +whisper_print_timings: sample time = 4.27 ms +whisper_print_timings: encode time = 8582.63 ms / 1430.44 ms per layer +whisper_print_timings: decode time = 436.16 ms / 72.69 ms per layer +whisper_print_timings: total time = 9370.90 ms +``` diff --git a/bindings/javascript/emscripten.cpp b/bindings/javascript/emscripten.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b442c1fcdbecf076f5d64f5475935017934afd6b --- /dev/null +++ b/bindings/javascript/emscripten.cpp @@ -0,0 +1,93 @@ +// +// This is the Javascript API of whisper.cpp +// +// Very crude at the moment. +// Feel free to contribute and make this better! +// +// See the tests/test-whisper.js for sample usage +// + +#include "whisper.h" + +#include +#include + +#include +#include + +struct whisper_context * g_context; + +EMSCRIPTEN_BINDINGS(whisper) { + emscripten::function("init", emscripten::optional_override([](const std::string & path_model) { + if (g_context == nullptr) { + g_context = whisper_init_from_file_with_params(path_model.c_str(), whisper_context_default_params()); + if (g_context != nullptr) { + return true; + } else { + return false; + } + } + + return false; + })); + + emscripten::function("free", emscripten::optional_override([]() { + if (g_context) { + whisper_free(g_context); + g_context = nullptr; + } + })); + + emscripten::function("full_default", emscripten::optional_override([](const emscripten::val & audio, const std::string & lang, bool translate) { + if (g_context == nullptr) { + return -1; + } + + struct whisper_full_params params = whisper_full_default_params(whisper_sampling_strategy::WHISPER_SAMPLING_GREEDY); + + params.print_realtime = true; + params.print_progress = false; + params.print_timestamps = true; + params.print_special = false; + params.translate = translate; + params.language = whisper_is_multilingual(g_context) ? lang.c_str() : "en"; + params.n_threads = std::min(8, (int) std::thread::hardware_concurrency()); + params.offset_ms = 0; + + std::vector pcmf32; + const int n = audio["length"].as(); + + emscripten::val heap = emscripten::val::module_property("HEAPU8"); + emscripten::val memory = heap["buffer"]; + + pcmf32.resize(n); + + emscripten::val memoryView = audio["constructor"].new_(memory, reinterpret_cast(pcmf32.data()), n); + memoryView.call("set", audio); + + // print system information + { + printf("\n"); + printf("system_info: n_threads = %d / %d | %s\n", + params.n_threads, std::thread::hardware_concurrency(), whisper_print_system_info()); + + printf("\n"); + printf("%s: processing %d samples, %.1f sec, %d threads, %d processors, lang = %s, task = %s ...\n", + __func__, int(pcmf32.size()), float(pcmf32.size())/WHISPER_SAMPLE_RATE, + params.n_threads, 1, + params.language, + params.translate ? "translate" : "transcribe"); + + printf("\n"); + } + + // run whisper + { + whisper_reset_timings(g_context); + whisper_full(g_context, params, pcmf32.data(), pcmf32.size()); + whisper_print_timings(g_context); + } + + return 0; + })); +} diff --git a/bindings/javascript/libwhisper.worker.js b/bindings/javascript/libwhisper.worker.js new file mode 100644 index 0000000000000000000000000000000000000000..db2083ad9edad527b81a79a633322a45e4e61dd2 --- /dev/null +++ b/bindings/javascript/libwhisper.worker.js @@ -0,0 +1 @@ +"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}whisper_factory(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage; diff --git a/bindings/javascript/package-tmpl.json b/bindings/javascript/package-tmpl.json new file mode 100644 index 0000000000000000000000000000000000000000..d8ba2106acf8cc61be46af0833b1d9a5ca2cce93 --- /dev/null +++ b/bindings/javascript/package-tmpl.json @@ -0,0 +1,26 @@ +{ + "name": "whisper.cpp", + "version": "@PROJECT_VERSION@", + "description": "Whisper speech recognition", + "main": "whisper.js", + "scripts": { + "test": "echo \"todo: add tests\" && exit 0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ggerganov/whisper.cpp" + }, + "keywords": [ + "openai", + "whisper", + "speech-to-text", + "speech-recognition", + "transformer" + ], + "author": "Georgi Gerganov", + "license": "MIT", + "bugs": { + "url": "https://github.com/ggerganov/whisper.cpp/issues" + }, + "homepage": "https://github.com/ggerganov/whisper.cpp#readme" +} diff --git a/bindings/javascript/package.json b/bindings/javascript/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2b3c806f3539beb5869a180fcec81fd22a7de843 --- /dev/null +++ b/bindings/javascript/package.json @@ -0,0 +1,26 @@ +{ + "name": "whisper.cpp", + "version": "1.6.2", + "description": "Whisper speech recognition", + "main": "whisper.js", + "scripts": { + "test": "echo \"todo: add tests\" && exit 0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ggerganov/whisper.cpp" + }, + "keywords": [ + "openai", + "whisper", + "speech-to-text", + "speech-recognition", + "transformer" + ], + "author": "Georgi Gerganov", + "license": "MIT", + "bugs": { + "url": "https://github.com/ggerganov/whisper.cpp/issues" + }, + "homepage": "https://github.com/ggerganov/whisper.cpp#readme" +} diff --git a/bindings/javascript/whisper.js b/bindings/javascript/whisper.js new file mode 100644 index 0000000000000000000000000000000000000000..77dd85552f44931b8778a77fd2f8e2993144ac65 --- /dev/null +++ b/bindings/javascript/whisper.js @@ -0,0 +1,19 @@ + +var whisper_factory = (() => { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; + return ( +function(moduleArg = {}) { + +function GROWABLE_HEAP_I8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP8}function GROWABLE_HEAP_U8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU8}function GROWABLE_HEAP_I16(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP16}function GROWABLE_HEAP_U16(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU16}function GROWABLE_HEAP_I32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP32}function GROWABLE_HEAP_U32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU32}function GROWABLE_HEAP_F32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF32}function GROWABLE_HEAP_F64(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF64}var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var ENVIRONMENT_IS_PTHREAD=Module["ENVIRONMENT_IS_PTHREAD"]||false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]";let nodeWorkerThreads;try{nodeWorkerThreads=require("worker_threads")}catch(e){console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?');throw e}global.Worker=nodeWorkerThreads.Worker}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}if(!ENVIRONMENT_IS_NODE){read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}if(ENVIRONMENT_IS_NODE){if(typeof performance=="undefined"){global.performance=require("perf_hooks").performance}}var defaultPrint=console.log.bind(console);var defaultPrintErr=console.error.bind(console);if(ENVIRONMENT_IS_NODE){defaultPrint=(...args)=>fs.writeSync(1,args.join(" ")+"\n");defaultPrintErr=(...args)=>fs.writeSync(2,args.join(" ")+"\n")}var out=Module["print"]||defaultPrint;var err=Module["printErr"]||defaultPrintErr;Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var wasmModule;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;assert(INITIAL_MEMORY>=65536,"INITIAL_MEMORY should be larger than STACK_SIZE, was "+INITIAL_MEMORY+"! (STACK_SIZE="+65536+")");if(ENVIRONMENT_IS_PTHREAD){wasmMemory=Module["wasmMemory"]}else{if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_MEMORY/65536,"maximum":2147483648/65536,"shared":true});if(!(wasmMemory.buffer instanceof SharedArrayBuffer)){err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag");if(ENVIRONMENT_IS_NODE){err("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and/or recent version)")}throw Error("bad memory")}}}updateMemoryViews();INITIAL_MEMORY=wasmMemory.buffer.byteLength;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(ENVIRONMENT_IS_PTHREAD)return;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(ENVIRONMENT_IS_PTHREAD)return;if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="data:application/octet-stream;base64,AGFzbQEAAAAByARKYAF/AX9gAX8AYAJ/fwBgA39/fwF/YAJ/fwF/YAN/f38AYAR/f39/AGAGf39/f39/AX9gBH9/f38Bf2AAAGAFf39/f38Bf2AFf39/f38AYAZ/f39/f38AYAh/f39/f39/fwF/YAABf2AHf39/f39/fwF/YAd/f39/f39/AGABfQF9YAV/fn5+fgBgA39+fwF+YAV/f39/fgF/YAR/f39/AX5gBH9+fn8AYAp/f39/f39/f39/AX9gB39/f39/fn4Bf2AGf39/f35+AX9gBX9/fn9/AGADf39/AXxgBH9/f38BfGAEf39+fgF/YAJ/fgBgAXwBfWACfH8BfGAFf39+fn4Bf2AIf39/f39/f38AYAx/f39/f39/f39/f38Bf2ADf35/AX9gD39/f39/f39/f39/f39/fwBgCn9/f39/f39/f38AYAt/f39/f39/f39/fwF/YAZ/fH9/f38Bf2AJf39/f39/f39/AGAFf39/f3wBf2AAAXxgA39/fgF/YAABfmACf3wAYAN/f30Bf2AEfn5+fgF/YAJ9fQF9YAJ+fwF/YAN/f3wBf2ABfABgCH9/fn5+f39/AX9gBX9/f399AGAGf39+fn9/AX9gAn5+AXxgAnx8AXxgBn9/f39+fgBgBH9/fn4AYAR/f35/AX9gA39/fwF9YAR/f39+AX5gA39/fgBgAn5+AX1gAn9/AX5gA35+fgF/YAF+AX9gAXwBfGABfwF+YAJ9fwF/YAV/f399fQBgBH9/f30AYAl/f39/f39/f38BfwKmAjABYQFiAAkBYQFjAAUBYQFkAAUBYQFlACsBYQFmAAEBYQFnAAsBYQFoABABYQFpAAQBYQFqAAABYQFrAAUBYQFsAAEBYQFtAAEBYQFuAAkBYQFvAAABYQFwAAgBYQFxAAMBYQFyAAIBYQFzAAUBYQF0AAgBYQF1AAABYQF2AAEBYQF3ABsBYQF4AAoBYQF5ABABYQF6AA4BYQFBAA4BYQFCAAoBYQFDAAQBYQFEAAQBYQFFAAABYQFGAAUBYQFHAAgBYQFIABwBYQFJAAEBYQFKAAEBYQFLAAgBYQFMAAMBYQFNAAgBYQFOAAkBYQFPAAEBYQFQAA4BYQFRAAIBYQFSAAYBYQFTAAIBYQFUAAEBYQFVAAYBYQFWAAQBYQFhAgOAAoCAAgOhB58HAQAF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AgQgBSAGGyEGA0ACQAJAAkACQAJAIAQiAigCFCACLQAbIgQgBMBBAEgiBxsiBCAGIAQgBkkiCRsiBQRAIAggAigCECACQRBqIAcbIgcgBRBKIgpFBEAgBCAGSw0CDAMLIApBAE4NAgwBCyAEIAZNDQILIAIhBSACKAIAIgQNBAwFCyAHIAggBRBKIgQNAQsgCQ0BDAQLIARBAE4NAwsgAigCBCIEDQALIAJBBGohBQtBIBAyIgQgAygCACIDKQIANwIQIAQgAygCCDYCGCADQgA3AgAgA0EANgIIIAQgAjYCCCAEQgA3AgAgBEEANgIcIAUgBDYCACAEIQIgASgCACgCACIDBEAgASADNgIAIAUoAgAhAgsgASgCBCACEKQBIAEgASgCCEEBajYCCEEBDAELIAIhBEEACzoABCAAIAQ2AgALBgAgABAvC4cFAgp/AX4jAEFAaiICJAAgAiAALQAIOgA4IAIgACkDADcDMCAAKAIUIQMgACgCECEEIABCADcDECAAKAIYIQUgAEEANgIYIAIgACgCRDYCKCACIAApAjw3AyAgAiAA/QACLP0LAxAgAiAA/QACHP0LAwAgACgCXCEGIAAoAlghByAAQgA3A1ggACgCTCEIIAAoAlAhCSAAKAJUIQogACgCSCELIAD9DAAAAAAAAAAAAAAAAAAAAAD9CwNIIAAgASkDADcDACAAIAEtAAg6AAggACABKAIQNgIQIAAgASgCFDYCFCAAIAEoAhg2AhggACkDYCEMIAFBADYCGCABQgA3AxAgACABKAJENgJEIAAgASkCPDcCPCAAIAH9AAIs/QsCLCAAIAH9AAIc/QsCHCAAQcgAaiABQcgAahCHAiABIAItADg6AAggASACKQMwNwMAIAEoAhAiAARAIAEgADYCFCAAEC8LIAEgBTYCGCABIAM2AhQgASAENgIQIAEgAigCKDYCRCABIAIpAyA3AjwgASAC/QADEP0LAiwgASAC/QADAP0LAhwgASgCSCIEBEAgASgCTCIDIAQiAEcEQANAIANBDGsiACgCACIFBEAgA0EIayAFNgIAIAUQLwsgACIDIARHDQALIAEoAkghAAsgASAENgJMIAAQLwsgASALNgJIIAEgCTYCUCABIAg2AkwgASgCVCIEBEAgASgCWCIDIAQiAEcEQANAIANBDGsiACgCACIFBEAgA0EIayAFNgIAIAUQLwsgACIDIARHDQALIAEoAlQhAAsgASAENgJYIAAQLwsgASAKNgJUIAEgDDcDYCABIAY2AlwgASAHNgJYIAJBQGskAAuMAgIDfwJ+AkAgACkDcCIEQgBSIAQgACkDeCAAKAIEIgEgACgCLCICa6x8IgVXcUUEQCMAQRBrIgIkAEF/IQECQCAAENACDQAgACACQQ9qQQEgACgCIBEDAEEBRw0AIAItAA8hAQsgAkEQaiQAIAEiA0EATg0BIAAoAgQhASAAKAIsIQILIABCfzcDcCAAIAE2AmggACAFIAIgAWusfDcDeEF/DwsgBUIBfCEFIAAoAgQhASAAKAIIIQICQCAAKQNwIgRQDQAgBCAFfSIEIAIgAWusWQ0AIAEgBKdqIQILIAAgAjYCaCAAIAUgACgCLCIAIAFrrHw3A3ggACABTwRAIAFBAWsgAzoAAAsgAwu4AQEDfwJAIAEQkwMiAiAALQALQQd2BH8gACgCCEH/////B3FBAWsFQQELIgNNBEACfyAALQALQQd2BEAgACgCAAwBCyAACyIDIAEgAkECdCIE/AoAACMAQRBrIgEkACAAIAIQmQEgAUEANgIMIAMgBGogASgCDDYCACABQRBqJAAMAQsgACADIAIgA2sCfyAALQALQQd2BEAgACgCBAwBCyAALQALQf8AcQsiAEEAIAAgAiABEIcDCwsJACAAIAEQiAMLEAAgABDwAyABEPADc0EBcwsQACAAEPEDIAEQ8QNzQQFzC+ECAQR/AkBB9Ik1/hIAAEEBcQ0AQfSJNRBURQ0AQZCINRClBCMAQSBrIgEkAAJAAkADQCABQQhqIgIgAEECdGogAEHlM0Hh+QBBASAAdEH/////B3EbEOUDIgM2AgAgA0F/Rg0BIABBAWoiAEEGRw0AC0G40QIhACACQbjRAkEYEEpFDQFB0NECIQAgAkHQ0QJBGBBKRQ0BQQAhAEHIiDUtAABFBEADQCAAQQJ0QZiINWogAEHh+QAQ5QM2AgAgAEEBaiIAQQZHDQALQciINUEBOgAAQbCINUGYiDUoAgA2AgALQZiINSEAIAFBCGoiAkGYiDVBGBBKRQ0BQbCINSEAIAJBsIg1QRgQSkUNAUEYEDsiAEUNACAAIAEpAgg3AgAgACABKQIYNwIQIAAgASkCEDcCCAwBC0EAIQALIAFBIGokAEGQiDUQ0wFB8Ik1IAA2AgBB9Ik1EFMLQfCJNSgCAAv2AQMCfAJ/AX4CfQJAIAC8IgNBFHZB/w9xIgRBqwhJDQBDAAAAACADQYCAgHxGDQEaIARB+A9PBEAgACAAkg8LIABDF3KxQl4EQCMAQRBrIgNDAAAAcDgCDCADKgIMQwAAAHCUDwsgAEO08c/CXUUNACMAQRBrIgNDAAAAEDgCDCADKgIMQwAAABCUDwtBgNsBKwMAQfjaASsDACAAu6IiASABQfDaASsDACIBoCICIAGhoSIBokGI2wErAwCgIAEgAaKiQZDbASsDACABokQAAAAAAADwP6CgIAK9IgVCL4YgBadBH3FBA3RB0NgBaikDAHy/orYLCwUAEAAACy4BAX9BBBBeIgBB6LUDNgIAIABBwLUDNgIAIABB1LUDNgIAIABBxLYDQQgQAgALMAECfyMAQRBrIgMkACADIAI3AwggACABQQEgA0EIakEAQQAQSSEEIANBEGokACAEC5IJAwl/AXsDfiMAQSBrIgkkAAJAIARFBEAMAQsgBCgCyAEiCEUEQCAEIQgMAQsgBCgCzAEgBWohBQsgAUEkbCIEQZibAWooAgAiDCADKQMAIARBlJsBajQCACISf6dsIQcCQCACQQJIDQACQCACQQJGBEBBASEEDAEL/QwAAAAAAQAAAAAAAAAAAAAAIAf9HAAhDyACQQFrIgZBAXIhBCAGQX5xIQpBACEHA0AgDyADIAdBA3RBCHJq/QADACAP/Q0AAQIDCAkKCwABAgMAAQID/bUBIQ8gB0ECaiIHIApHDQALIA8gDyAP/Q0EBQYHAAECAwABAgMAAQID/bUB/RsAIQcgBiAKRg0BCwNAIAcgAyAEQQN0aigCAGwhByAEQQFqIgQgAkcNAAsLAkACQAJ/IAgEQCAFIAdqIQYgCCkDICEQIAgpAxghEQJ/IAgoAgAiBEEQa0FxTQRAIARBJGxBmJsBaigCACAIKAIwIAgoAhBBAWtsaiAIKAI0IBGnQQFrbGogCCgCOCAQp0EBa2xqIAgoAjwgCCgCKEEBa2xqDAELIAg1AjQgEUIBfX4gCCkDECAINQIwfiAEQSRsQZSbAWo1AgB/fCAINQI4IBBCAX1+fCAINQI8IAgpAyhCAX1+fKcLIAZJDQMgCCgC0AEiBCAFakEAIAQbIQtBAAwBC0EAIAAtAAkNABogACgCICIGRQRAIAcMAQsgByAAKAIYIgdqIgQgACgCHCIKSwRAIAkgCjYCCCAJIAQ2AgQgCUHzGTYCAEG+8wAgCRCzAUEAIQYMAgsgACAENgIYIAYgB2ohC0EACyEKQQAhBCAAQQAgCkGoAmoQsAIhByAAKAIEIg0gBygCACIHaiIGIAI2AgwgBkIANwIEIAYgATYCACAGQeCiAf0ABAD9CwMQIAZBIGpB8KIB/QAEAP0LAwAgBkEwakEAQZgB/AsAIAYgBkGoAmogCyAKGzYC0AEgBiAFNgLMASAGIAg2AsgBIAZB1AFqQQBB1AD8CwACQCACQQBMDQACQCACQQhJDQAgByANaiADa0EQakEQSQ0AIAJBfnEhBEEAIQcDQCAGIAdBA3QiAWogASADav0AAwD9CwMQIAdBAmoiByAERw0ACyACIARGDQELIARBf3MgAmohDiACIARrQQNxIgUEQEEAIQcDQCAGIARBA3QiCGogAyAIaikDADcDECAEQQFqIQQgB0EBaiIHIAVHDQALCyAOQQJNDQADQCAGQRBqIgUgBEEDdCIBaiABIANqKQMANwMAIAUgAUEIaiIHaiADIAdqKQMANwMAIAUgAUEQaiIHaiADIAdqKQMANwMAIAUgAUEYaiIBaiABIANqKQMANwMAIARBBGoiBCACRw0ACwsgBiAMNgIwIAYgDCAGKQMQIBJ/p2wiATYCNCAGIAEgBigCGGwiATYCOCAGIAEgBigCIGw2AjwgACAAKAIMQQFqNgIMCyAJQSBqJAAgBg8LQbzDAigCABAwGiAJQebVADYCGCAJQbETNgIUIAlB5CY2AhBBuMMCKAIAQcvkACAJQRBqEDEQAAALgQEBAn8CQAJAIAJBBE8EQCAAIAFyQQNxDQEDQCAAKAIAIAEoAgBHDQIgAUEEaiEBIABBBGohACACQQRrIgJBA0sNAAsLIAJFDQELA0AgAC0AACIDIAEtAAAiBEYEQCABQQFqIQEgAEEBaiEAIAJBAWsiAg0BDAILCyADIARrDwtBAAvFCgIFfxF+IwBB4ABrIgUkACAEQv///////z+DIQwgAiAEhUKAgICAgICAgIB/gyEKIAJC////////P4MiDUIgiCEOIARCMIinQf//AXEhBwJAAkAgAkIwiKdB//8BcSIJQf//AWtBgoB+TwRAIAdB//8Ba0GBgH5LDQELIAFQIAJC////////////AIMiC0KAgICAgIDA//8AVCALQoCAgICAgMD//wBRG0UEQCACQoCAgICAgCCEIQoMAgsgA1AgBEL///////////8AgyICQoCAgICAgMD//wBUIAJCgICAgICAwP//AFEbRQRAIARCgICAgICAIIQhCiADIQEMAgsgASALQoCAgICAgMD//wCFhFAEQCACIAOEUARAQoCAgICAgOD//wAhCkIAIQEMAwsgCkKAgICAgIDA//8AhCEKQgAhAQwCCyADIAJCgICAgICAwP//AIWEUARAIAEgC4QhGUIAIQEgGVAEQEKAgICAgIDg//8AIQoMAwsgCkKAgICAgIDA//8AhCEKDAILIAEgC4RQBEBCACEBDAILIAIgA4RQBEBCACEBDAILIAtC////////P1gEQCAFQdAAaiABIA0gASANIA1QIgYbeSAGQQZ0rXynIgZBD2sQZkEQIAZrIQYgBSkDWCINQiCIIQ4gBSkDUCEBCyACQv///////z9WDQAgBUFAayADIAwgAyAMIAxQIggbeSAIQQZ0rXynIghBD2sQZiAGIAhrQRBqIQYgBSkDSCEMIAUpA0AhAwsgA0IPhiILQoCA/v8PgyICIAFCIIgiBH4iECALQiCIIhMgAUL/////D4MiAX58Ig9CIIYiESABIAJ+fCILIBFUrSACIA1C/////w+DIg1+IhUgBCATfnwiESAMQg+GIhIgA0IxiIRC/////w+DIgMgAX58IhQgDyAQVK1CIIYgD0IgiIR8Ig8gAiAOQoCABIQiDH4iFiANIBN+fCIOIBJCIIhCgICAgAiEIgIgAX58IhAgAyAEfnwiEkIghnwiF3whASAHIAlqIAZqQf//AGshBgJAIAIgBH4iGCAMIBN+fCIEIBhUrSAEIAQgAyANfnwiBFatfCACIAx+fCAEIAQgESAVVK0gESAUVq18fCIEVq18IAMgDH4iAyACIA1+fCICIANUrUIghiACQiCIhHwgBCACQiCGfCICIARUrXwgAiACIBAgElatIA4gFlStIA4gEFatfHxCIIYgEkIgiIR8IgJWrXwgAiACIA8gFFStIA8gF1atfHwiAlatfCIEQoCAgICAgMAAg0IAUgRAIAZBAWohBgwBCyALQj+IIRogBEIBhiACQj+IhCEEIAJCAYYg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AisDACADokHAoAIrAwCgoCAEoiABQRd1t0GooAIrAwCiIAJBsJ4CaisDAKAgA6CgtiEACyAAC+4CAgZ/A34jAEFAaiIDJAACQAJAIAEpAxAgAikDEFINACACKQMgIgkgASkDIIFCAFINACACKQMoIgogASkDKIFCAFINACABKAIwIAEoAjRLDQECfwJAIAEoAogBDQAgAigCiAENAEEADAELQQELIQggAyABKQMYNwMgIAIpAxghCyADIAo3AzggAyAJNwMwIAMgCzcDKCAAQQAgASgCDCIEIAIoAgwiByAEIAdKGyADQSBqQQBBABBJIgRBFzYCQCAIBEAgACAEKAIAIAQoAgwgBEEQakEAQQAQSSEFCyAEIAE2AowBIAQgBTYCiAEgBCACNgKQASADQUBrJAAgBA8LQbzDAigCABAwGiADQZTXADYCGCADQecfNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALQbzDAigCABAwGiADQdvXADYCCCADQegfNgIEIANB5CY2AgBBuMMCKAIAQcvkACADEDEQAAALoQICA38BfgJAIAAoAgwiAkEBcQRAQRgQMiECIAAoAiQoAgQhAyACQfysATYCACACIAM2AgQgAkEIaiAAKAIAIgM2AgAgA0EEakEB/h4CABogAiAAKQIEIgU3AgwgAiAFpyIDIAEgAygCACgCFBEEADoAFCAAKAIkIAI2AgQMAQsgAkEIcQRAQRgQMiECIAAoAiQoAgQhAyACQditATYCACACIAM2AgQgAkEIaiAAKAIAIgM2AgAgA0EEakEB/h4CABogACkCBCEFIAIgAToAFCACIAU3AgwgACgCJCACNgIEDAELQQwQMiECIAAoAiQiAygCBCEEIAIgAToACCACQbSuATYCACACIAQ2AgQgAyACNgIECyAAIAAoAiQoAgQ2AiQLdQEBfyMAQRBrIgIkACACIAE6AA8CQCAALQALQQd2BEAgACgCACEBIABBATYCBAwBCyAAIgEgAS0AC0GAAXFBAXI6AAsgASABLQALQf8AcToACwsgASACLQAPOgAAIAJBADoADiABIAItAA46AAEgAkEQaiQAC6sBAgJ+AX8gACkDICEBIAApAxghAiAAKAIAIgNBEGtBcU0EQCADQSRsQZibAWooAgAgACgCMCAAKAIQQQFrbGogACgCNCACp0EBa2xqIAAoAjggAadBAWtsaiAAKAI8IAAoAihBAWtsag8LIAA1AjQgAkIBfX4gACkDECAANQIwfiADQSRsQZSbAWo1AgB/fCAANQI4IAFCAX1+fCAANQI8IAApAyhCAX1+fKcLDQAgACgCABD7AxogAAsNACAAKAIAEP0DGiAACw4AIABB0ABqEDtB0ABqC8EBAQN/IwBBEGsiBSQAAkAgAiAALQALQQd2BH8gACgCCEH/////B3FBAWsFQQoLIgQCfyAALQALQQd2BEAgACgCBAwBCyAALQALQf8AcQsiA2tNBEAgAkUNAQJ/IAAtAAtBB3YEQCAAKAIADAELIAALIgQgA2ogASACEHcgACACIANqIgEQmQEgBUEAOgAPIAEgBGogBS0ADzoAAAwBCyAAIAQgAiAEayADaiADIANBACACIAEQzAELIAVBEGokACAAC3UBAX4gACABIAR+IAIgA358IANCIIgiAiABQiCIIgR+fCADQv////8PgyIDIAFC/////w+DIgF+IgVCIIggAyAEfnwiA0IgiHwgASACfiADQv////8Pg3wiAUIgiHw3AwggACAFQv////8PgyABQiCGhDcDAAsYACAALQAAQSBxRQRAIAEgAiAAEM4CGgsLqwEBBn8jAEEQayICJAAgACgCBCEDIAEgACgCACIEcCIFIQACQAJAA0ACQCADIABBAnRqIgYoAgAiB0UNACABIAdGDQAgAEEBaiIAQQAgACAERxsiACAFRw0BDAILCyAAQX9HDQELQbzDAigCABAwGiACQbUwNgIIIAJBlvEANgIEIAJB5CY2AgBBuMMCKAIAQcvkACACEDEQAAALIAYgATYCACACQRBqJAAgAAtGAQJ/IwBBEGsiBSQAIAUgAjYCDCAFIAQ2AgggBUEEaiAFQQxqEH8hBiAAIAEgAyAFKAIIELABIQAgBhB+IAVBEGokACAAC+0BAQJ/An8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELIQQCQCACIAFrQQVIDQAgBEUNACABIAIQ6gEgAkEEayEEAn8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELAn8gAC0AC0EHdgRAIAAoAgAMAQsgAAsiAmohBQJAA0ACQCACLAAAIQAgASAETw0AAkAgAEEATA0AIABB/wBODQAgACABKAIARw0DCyABQQRqIQEgAiAFIAJrQQFKaiECDAELCyAAQQBMDQEgAEH/AE4NASACLAAAIAQoAgBBAWtLDQELIANBBDYCAAsLdgEBfyMAQRBrIgIkACAALQALQQd2BEAgACAAKAIAIAAoAghB/////wdxEPEBCyAAIAEoAgg2AgggACABKQIANwIAIAEgAS0AC0GAAXE6AAsgASABLQALQf8AcToACyACQQA6AA8gASACLQAPOgAAIAJBEGokAAtQAQF+AkAgA0HAAHEEQCABIANBQGqthiECQgAhAQwBCyADRQ0AIAIgA60iBIYgAUHAACADa62IhCECIAEgBIYhAQsgACABNwMAIAAgAjcDCAtvAQF/IwBBgAJrIgUkAAJAIAIgA0wNACAEQYDABHENACAFIAFB/wFxIAIgA2siA0GAAiADQYACSSIBGxCgASABRQRAA0AgACAFQYACEGEgA0GAAmsiA0H/AUsNAAsLIAAgBSADEGELIAVBgAJqJAALegEDfwJAAkAgACIBQQNxRQ0AIAEtAABFBEBBAA8LA0AgAUEBaiIBQQNxRQ0BIAEtAAANAAsMAQsDQCABIgJBBGohASACKAIAIgNBf3MgA0GBgoQIa3FBgIGChHhxRQ0ACwNAIAIiAUEBaiECIAEtAAANAAsLIAEgAGsLOAIDfwF+IwBBEGsiACQAIAAQ1wEgACkDACEDIAAoAgghAiAAQRBqJAAgAkHoB22sIANCwIQ9fnwL9gIDA38BfAF9IwBBEGsiASQAAn0gALwiA0H/////B3EiAkHan6T6A00EQEMAAIA/IAJBgICAzANJDQEaIAC7EIQBDAELIAJB0aftgwRNBEAgAkHkl9uABE8EQEQYLURU+yEJQEQYLURU+yEJwCADQQBIGyAAu6AQhAGMDAILIAC7IQQgA0EASARAIAREGC1EVPsh+T+gEIMBDAILRBgtRFT7Ifk/IAShEIMBDAELIAJB1eOIhwRNBEAgAkHg27+FBE8EQEQYLURU+yEZQEQYLURU+yEZwCADQQBIGyAAu6AQhAEMAgsgA0EASARARNIhM3982RLAIAC7oRCDAQwCCyAAu0TSITN/fNkSwKAQgwEMAQsgACAAkyACQYCAgPwHTw0AGgJAAkACQAJAIAAgAUEIahCvBEEDcQ4DAAECAwsgASsDCBCEAQwDCyABKwMImhCDAQwCCyABKwMIEIQBjAwBCyABKwMIEIMBCyEFIAFBEGokACAFC9YBAQJ/IwBBEGsiBCQAAkACQCACQQtJBEAgACIDIAAtAAtBgAFxIAJyOgALIAAgAC0AC0H/AHE6AAsMAQsgAkHv////B0sNASAEQQhqIAAgAkELTwR/IAJBEGpBcHEiAyADQQFrIgMgA0ELRhsFQQoLQQFqEMMBIAQoAgwaIAAgBCgCCCIDNgIAIAAgACgCCEGAgICAeHEgBCgCDEH/////B3FyNgIIIAAgACgCCEGAgICAeHI2AgggACACNgIECyADIAEgAkEBahB3IARBEGokAA8LEE0ACwoAIABBlIo1EHkLBABBAAuJAgEHfyABIAAoAggiAyAAKAIEIgJrQQJ1TQRAIAAgAQR/IAJBACABQQJ0IgD8CwAgACACagUgAgs2AgQPCwJAIAIgACgCACIFa0ECdSIHIAFqIgRBgICAgARJBEBB/////wMgAyAFayIDQQF1IgggBCAEIAhJGyADQfz///8HTxsiAwRAIANBgICAgARPDQIgA0ECdBAyIQYLIAdBAnQgBmoiBEEAIAFBAnQiAfwLACABIARqIQEgAiAFRwRAA0AgBEEEayIEIAJBBGsiAioCADgCACACIAVHDQALCyAAIAYgA0ECdGo2AgggACABNgIEIAAgBDYCACAFBEAgBRAvCw8LEDYACxBHAAstACACRQRAIAAoAgQgASgCBEYPCyAAIAFGBEBBAQ8LIAAoAgQgASgCBBCfAUULUgEBfyABQQFrIgJBEE0EfyACQQJ0QdypA2ooAgAFQcYiCyECIABB6LUDNgIAIABB7LYDNgIAIABBBGogAhCKAyAAIAE2AgggAEGooQM2AgAgAAvHCQIEfwZ+IwBB8ABrIgYkACAEQv///////////wCDIQkCQAJAIAFQIgUgAkL///////////8AgyIKQoCAgICAgMD//wB9QoCAgICAgMCAgH9UIApQG0UEQCADQgBSIAlCgICAgICAwP//AH0iC0KAgICAgIDAgIB/ViALQoCAgICAgMCAgH9RGw0BCyAFIApCgICAgICAwP//AFQgCkKAgICAgIDA//8AURtFBEAgAkKAgICAgIAghCEEIAEhAwwCCyADUCAJQoCAgICAgMD//wBUIAlCgICAgICAwP//AFEbRQRAIARCgICA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Qd/bv4UETQRAIAC7IQQgA0EASARAIARE0iEzf3zZEkCgEIQBIQAMAwsgBETSITN/fNkSwKAQhAGMIQAMAgtEGC1EVPshGUBEGC1EVPshGcAgA0EASBsgALugEIMBIQAMAQsgAkGAgID8B08EQCAAIACTIQAMAQsCQAJAAkACQCAAIAFBCGoQrwRBA3EOAwABAgMLIAErAwgQgwEhAAwDCyABKwMIEIQBIQAMAgsgASsDCJoQgwEhAAwBCyABKwMIEIQBjCEACyABQRBqJAAgAAuPBAEDfyACQYAETwRAIAAgASAC/AoAACAADwsgACACaiEEAkAgACABc0EDcUUEQAJ/IAAgAEEDcUUNABogACACRQ0AGiAAIAEgAEF/cyICIAQgAEEBaiIDIAMgBEkbaiIDIAJBA3EiAiACIANLG0EBaiIC/AoAACABIAJqIQEgACACagshAgJAIARBfHEiA0HAAEkNACACIANBQGoiBUsNAANAIAIgASgCADYCACACIAEoAgQ2AgQgAiABKAIINgIIIAIgASgCDDYCDCACIAEoAhA2AhAgAiABKAIUNgIUIAIgASgCGDYCGCACIAEoAhw2AhwgAiABKAIgNgIgIAIgASgCJDYCJCACIAEoAig2AiggAiABKAIsNgIsIAIgASgCMDYCMCACIAEoAjQ2AjQgAiABKAI4NgI4IAIgASgCPDYCPCABQUBrIQEgAkFAayICIAVNDQALCyACIANPDQEgAiABIAJBf3MgAyACQQRqIgUgAyAFSxtqQXxxQQRqIgP8CgAAIAEgA2ohASACIANqIQIMAQsgBEEESQRAIAAhAgwBCyAAIARBBGsiA0sEQCAAIQIMAQsgACECA0AgAiABLQAAOgAAIAIgAS0AAToAASACIAEtAAI6AAIgAiABLQADOgADIAFBBGohASACQQRqIgIgA00NAAsLIAIgBEkEQCACIAEgBCACa/wKAAALIAALIAAjAEEQayIBJAAgAEIANwIAIABBADYCCCABQRBqJAALugcBCH8jAEHQAGsiBCQAIAQgACkCGDcDSAJAAkACQAJ/IwBBIGsiAiQAIAQoAkwhBiABIAQoAkgiB3AiCCEDAkADQAJAIAYgA0ECdGoiCSgCACIFRQ0AIAEgBUYNACADQQFqIgNBACADIAdHGyIDIAhHDQEMAgsLIANBf0YNAAJA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KAIAKAIkEQAADAELIAgtAAALwCIGQQBOBH8gAygCCCAGQf8BcUECdGooAgBBwABxQQBHBUEAC0UNACADIAZBACADKAIAKAIkEQMAIQEDQAJAIAAQXRogAUEwayEBIAAgB0EMahBDDQAgBEECSA0AAn8gACgCACIFKAIMIgYgBSgCEEYEQCAFIAUoAgAoAiQRAAAMAQsgBi0AAAvAIgVBAE4EfyADKAIIIAVB/wFxQQJ0aigCAEHAAHFBAEcFQQALRQ0DIARBAWshBCADIAVBACADKAIAKAIkEQMAIAFBCmxqIQEMAQsLQQIhBSAAIAdBDGoQQ0UNAQsgAiACKAIAIAVyNgIACyAHQRBqJAAgAQuZAQEEfyMAQRBrIgQkACAEIAE2AgwgBCADNgIIIARBBGogBEEMahB/IQcgBCgCCCEDIwBBEGsiASQAIAEgAzYCDCABIAM2AghBfyEFAkBBAEEAIAIgAxCwASIDQQBIDQAgACADQQFqIgMQOyIANgIAIABFDQAgACADIAIgASgCDBCwASEFCyABQRBqJAAgBxB+IARBEGokACAFCy4AAkAgACgCBEHKAHEiAARAIABBwABGBEBBCA8LIABBCEcNAUEQDwtBAA8LQQoL+QECA34CfyMAQRBrIgUkAAJ+IAG9IgNC////////////AIMiAkKAgICAgICACH1C/////////+//AFgEQCACQjyGIQQgAkIEiEKAgICAgICAgDx8DAELIAJCgICAgICAgPj/AFoEQCADQjyGIQQgA0IEiEKAgICAgIDA//8AhAwBCyACUARAQgAMAQsgBSACQgAgA6dnQSBqIAJCIIinZyACQoCAgIAQVBsiBkExahBmIAUpAwAhBCAFKQMIQoCAgICAgMAAhUGM+AAgBmutQjCGhAshAiAAIAQ3AwAgACACIANCgICAgICAgICAf4OENwMIIAVBEGokAAsJACAAQQEQtQELKAEBfyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwsMACAAKAIAIAEQ6QQLbAECfyAAKAIEIgEEQCABKAIIIgIEQCACEC8LIAEoAgwiAgRAIAIQLwsgASgCFCICBEAgAhAvCyABKAIYIgIEQCACEC8LIAEQLwsgACgCACIBBEAgAS0ABARAIAEoAgAQpwELIAEQLwsgABAvC40F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AgsgACAINgIcIAAgCTYCGCAAIAU2AhQgAkUNASACEC8PCyAAKAIcIQMgACgCGCECAkAgAC0AWgRAIAIgA0kNBSACIAAoAhQiBmsiB0EBaiIFQQBIDQQgB0H/////ByADIAZrIgNBAXQiBCAFIAQgBUsbIANB/////wNPGyIEBH8gBBAyBUEACyIFaiIDIAE6AAAgBCAFaiEIIANBAWohCQJAIAIgBkYEQCADIQUMAQsCQAJAIAdBEEkNACAGIAIgBWprIAJqQRBJDQAgA0EQayEKIAJBEGshCyACIAdBcHEiBGshAiADIARrIQNBACEBA0AgCiABayALIAFr/QAAAP0LAAAgAUEQaiIBIARHDQALIAQgB0YNAQsgBkF/cyACaiENIAIgBmtBA3EiBARAQQAhAQNAIANBAWsiAyACQQFrIgItAAA6AAAgAUEBaiIBIARHDQALCyANQQNJDQADQCADQQFrIAJBAWstAAA6AAAgA0ECayACQQJrLQAAOgAAIANBA2sgAkEDay0AADoAACADQQRrIgMgAkEEayICLQAAOgAAIAIgBkcNAAsLIAAoAhQhAgsgACAINgIcIAAgCTYCGCAAIAU2AhQgAg0BDAILIAIgA0cNBCACIAAoAhQiB2siBkEBaiIDQQBIDQMgBkH/////ByAGQQF0IgUgAyADIAVJGyAGQf////8DTxsiBAR/IAQQMgVBAAsiBWoiAyABOgAAIAQgBWohCCADQQFqIQkCQCACIAdGBEAgAyEFDAELAkACQCAGQRBJDQAgByACIAVqayACakEQSQ0AIANBEGshCiACQRBrIQsgAiAGQXBxIgRrIQIgAyAEayEDQQAhAQNAIAogAWsgCyABa/0AAAD9CwAAIAFBEGoiASAERw0ACyAEIAZGDQELIAdBf3MgAmohDiACIAdrQQNxIgQEQEEAIQEDQCADQQFrIgMgAkEBayICLQAAOgAAIAFBAWoiASAERw0ACwsgDkEDSQ0AA0AgA0EBayACQQFrLQAAOgAAIANBAmsgAkECay0AADoAACADQQNrIAJBA2stAAA6AAAgA0EEayIDIAJBBGsiAi0AADoAACACIAdHDQALCyAAKAIUIQILIAAgCDYCHCAAIAk2AhggACAFNgIUIAJFDQELIAIQLwsPCxA2AAsQNgALIAIgAToAACAAIAJBAWo2AhgLlAQBBH8gASAAIAFGIgI6AAwCQCACDQADQCABKAIIIgItAAwNAQJAIAIgAigCCCIDKAIAIgRGBEACQCADKAIEIgRFDQAgBC0ADA0ADAILAkAgASACKAIARgRAIAIhAQwBCyACIAIoAgQiASgCACIANgIEIAEgAAR/IAAgAjYCCCACKAIIBSADCzYCCCACKAIIIgAgACgCACACR0ECdGogATYCACABIAI2AgAgAiABNgIIIAEoAggiAygCACECCyABQQE6AAwgA0EAOgAMIAMgAigCBCIANgIAIAAEQCAAIAM2AggLIAIgAygCCDYCCCADKAIIIgAgACgCACADR0ECdGogAjYCACACIAM2AgQgAyACNgIIDwsCQCAERQ0AIAQtAAwNAAwBCwJAIAEgAigCAEcEQCACIQEMAQsgAiABKAIEIgA2AgAgASAABH8gACACNgIIIAIoAggFIAMLNgIIIAIoAggiACAAKAIAIAJHQQJ0aiABNgIAIAEgAjYCBCACIAE2AgggASgCCCEDCyABQQE6AAwgA0EAOgAMIAMgAygCBCIAKAIAIgE2AgQgAQRAIAEgAzYCCAsgACADKAIINgIIIAMoAggiASABKAIAIANHQQJ0aiAANgIAIAAgAzYCACADIAA2AggMAgsgBEEMaiEFIAJBAToADCADIAAgA0Y6AAwgBUEBOgAAIAMiASAARw0ACwsLnAIBBH8gACgCiAEiAQRAIAAgATYCjAEgARAvCyAAKAJ8IgEEQCAAIAE2AoABIAEQLwsgACgCcCIBBEAgACABNgJ0IAEQLwsgACgCZCIBBEAgACABNgJoIAEQLwsgACgCRCIDBEAgAyECIAMgACgCSCIBRwRAA0AgAUEMayICKAIAIgQEQCABQQhrIAQ2AgAgBBAvCyACIgEgA0cNAAsgACgCRCECCyAAIAM2AkggAhAvCyAAKAI4IgMEQCADIQIgAyAAKAI8IgFHBEADQCABQQxrIgIoAgAiBARAIAFBCGsgBDYCACAEEC8LIAIiASADRw0ACyAAKAI4IQILIAAgAzYCPCACEC8LIAAoAgAiAQRAIAAgATYCBCABEC8LC3ABA38gARBoIgJB8P///wdJBEACQCACQQpNBEAgACACOgALIAAhAwwBCyACQQ9yQQFqIgQQMiEDIAAgBEGAgICAeHI2AgggACADNgIAIAAgAjYCBAsgAyABIAL8CgAAIAIgA2pBADoAACAADwsQTQALHgEBfyAABEAgACgCACIBBEAgACABEQEACyAAEC8LC3sBAn8jAEEQayICJAAgACgCBCEDIAAgARB9AkAgAyAAKAIEIgNODQAgACgCDCADQQJ0akEEaygCACABRg0AQbzDAigCABAwGiACQekTNgIIIAJByPkANgIEIAJB5CY2AgBBuMMCKAIAQcvkACACEDEQAAALIAJBEGokAAsTACABQQF0QdCqA2pBAiAAEIEEC84BAQF/An8jAEEwayIDJAAgASgCiAFFBEAgACABKAIAIAEoAgwgAUEQakEAQQAQSSIARQRAQbzDAigCABAwGiADQdcvNgIYIANBxhQ2AhQgA0HkJjYCEEG4wwIoAgBBy+QAIANBEGoQMRAAAAsgACABNgKMASAAQQA2AogBIABBEzYCQCAAIAI4AkQgA0EwaiQAIAAMAQtBvMMCKAIAEDAaIANBmyE2AiggA0HcHjYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxEAAACwv0AgIDfwh+IwBBMGsiAyQAAn8CQAJAIAEpAxAiBiACKQMQIgeBQgBSDQAgASkDGCIIIAIpAxgiCYFCAFINACABKQMgIgogAikDICILgUIAUg0AIAEpAygiDCACKQMoIg2BQgBSDQAgAUEQaiEEAkAgASgCiAENACACKAKIAQ0ADAILAkAgBiAHUg0AIAggCVINACAKIAtSDQBBASEFIAwgDVENAgtBvMMCKAIAEDAaIANBq9cANgIYIANByBo2AhQgA0HkJjYCEEG4wwIoAgBBy+QAIANBEGoQMRAAAAtBvMMCKAIAEDAaIANBpdgANgIoIANBwho2AiQgA0HkJjYCIEG4wwIoAgBBy+QAIANBIGoQMRAAAAsgACABKAIAIAEoAgwgBEEAQQAQSSIEQQY2AkBBACAFRQ0AGiAAIAQoAgAgBCgCDCAEQRBqQQBBABBJCyEAIAQgATYCjAEgBCAANgKIASAEIAI2ApABIANBMGokACAEC3YBAX8jAEEQayICJAAgAiAANgIMAkAgACABRg0AA0AgAiABQQFrIgE2AgggACABTw0BIAIoAgwiAC0AACEBIAAgAigCCCIALQAAOgAAIAAgAToAACACIAIoAgxBAWoiADYCDCACKAIIIQEMAAsACyACQRBqJAAL2wgBAX9BAEEB/h4CkNY0QQBKBEADQEEAQQH+JQKQ1jQaEAMQ1gFBAEEB/h4CkNY0QQBKDQALCwJAAkAgAEHguwNGDQAgAEGUvANGBEBBASEBDAELIABByLwDRgRAQQIhAQwBCyAAQfy8A0YEQEEDIQEMAQsgAEGwvQNGBEBBBCEBDAELIABB5L0DRgRAQQUhAQwBCyAAQZi+A0YEQEEGIQEMAQsgAEHMvgNGBEBBByEBDAELIABBgL8DRgRAQQghAQwBCyAAQbS/A0YEQEEJIQEMAQsgAEHovwNGBEBBCiEBDAELIABBnMADRgRAQQshAQwBCyAAQdDAA0YEQEEMIQEMAQsgAEGEwQNGBEBBDSEBDAELIABBuMEDRgRAQQ4hAQwBCyAAQezBA0YEQEEPIQEMAQsgAEGgwgNGBEBBECEBDAELIABB1MIDRgRAQREhAQwBCyAAQYjDA0YEQEESIQEMAQsgAEG8wwNGBEBBEyEBDAELIABB8MMDRgRAQRQhAQwBCyAAQaTEA0YEQEEVIQEMAQsgAEHYxANGBEBBFiEBDAELIABBjMUDRgRAQRchAQwBCyAAQcDFA0YEQEEYIQEMAQsgAEH0xQNGBEBBGSEBDAELIABBqMYDRgRAQRohAQwBCyAAQdzGA0YEQEEbIQEMAQsgAEGQxwNGBEBBHCEBDAELIABBxMcDRgRAQR0hAQwBCyAAQfjHA0YEQEEeIQEMAQsgAEGsyANGBEBBHyEBDAELIABB4MgDRgRAQSAhAQwBCyAAQZTJA0YEQEEhIQEMAQsgAEHIyQNGBEBBIiEBDAELIABB/MkDRgRAQSMhAQwBCyAAQbDKA0YEQEEkIQEMAQsgAEHkygNGBEBBJSEBDAELIABBmMsDRgRAQSYhAQwBCyAAQczLA0YEQEEnIQEMAQsgAEGAzANGBEBBKCEBDAELIABBtMwDRgRAQSkhAQwBCyAAQejMA0YEQEEqIQEMAQsgAEGczQNGBEBBKyEBDAELIABB0M0DRgRAQSwhAQwBCyAAQYTOA0YEQEEtIQEMAQsgAEG4zgNGBEBBLiEBDAELIABB7M4DRgRAQS8hAQwBCyAAQaDPA0YEQEEwIQEMAQsgAEHUzwNGBEBBMSEBDAELIABBiNADRgRAQTIhAQwBCyAAQbzQA0YEQEEzIQEMAQsgAEHw0ANGBEBBNCEBDAELIABBpNEDRgRAQTUhAQwBCyAAQdjRA0YEQEE2IQEMAQsgAEGM0gNGBEBBNyEBDAELIABBwNIDRgRAQTghAQwBCyAAQfTSA0YEQEE5IQEMAQsgAEGo0wNGBEBBOiEBDAELIABB3NMDRgRAQTshAQwBCyAAQZDUA0YEQEE8IQEMAQsgAEHE1ANGBEBBPSEBDAELIABB+NQDRgRAQT4hAQwBCyAAQazVA0cNAUE/IQELIAFBNGxB3LsDakEAOgAAIAAtAAhFDQAgACgCBBAvC0EAQQH+JQKQ1jQaC9sBAgF/An5BASEEAkAgAEIAUiABQv///////////wCDIgVCgICAgICAwP//AFYgBUKAgICAgIDA//8AURsNACACQgBSIANC////////////AIMiBkKAgICAgIDA//8AViAGQoCAgICAgMD//wBRGw0AIAAgAoQgBSAGhIRQBEBBAA8LIAEgA4NCAFkEQEF/IQQgACACVCABIANTIAEgA1EbDQEgACAChSABIAOFhEIAUg8LQX8hBCAAIAJWIAEgA1UgASADURsNACAAIAKFIAEgA4WEQgBSIQQLIAQLUAEBfgJAIANBwABxBEAgAiADQUBqrYghAUIAIQIMAQsgA0UNACACQcAAIANrrYYgASADrSIEiIQhASACIASIIQILIAAgATcDACAAIAI3AwgLqQEBA38jAEGgAWsiBCQAIAQgACAEQZ4BaiABGyIFNgKUAUF/IQAgBCABQQFrIgZBACABIAZPGzYCmAEgBEEAQZAB/AsAIARBfzYCTCAEQc8BNgIkIARBfzYCUCAEIARBnwFqNgIsIAQgBEGUAWo2AlQCQCABQQBIBEAjA0EcakE9NgIADAELIAVBADoAACAEIAIgA0HNAUHOARDDAiEACyAEQaABaiQAIAALqAEAAkAgAUGACE4EQCAARAAAAAAAAOB/oiEAIAFB/w9JBEAgAUH/B2shAQwCCyAARAAAAAAAAOB/oiEAQf0XIAEgAUH9F04bQf4PayEBDAELIAFBgXhKDQAgAEQAAAAAAABgA6IhACABQbhwSwRAIAFByQdqIQEMAQsgAEQAAAAAAABgA6IhAEHwaCABIAFB8GhMG0GSD2ohAQsgACABQf8Haq1CNIa/ogswAQF/IAEjAyICKAJIIABBAnRqIgAoAgBHBEAgACABNgIAIAIgAi0AKkEBcjoAKgsLJgEBfyMAQRBrIgIkACACIAE2AgxBsLoDIAAgARCGBCACQRBqJAALyQUEBH8CfAF9AX4gAbwiBEEBdEGAgIAIakGBgIAISSECAkACQAJAAkAgALwiA0GAgID8B2tBgICAiHhPBEAgAg0BDAMLIAJFDQELQwAAgD8hCCADQYCAgPwDRg0CIARBAXQiAkUNAiACQYGAgHhJIANBAXQiAkGAgIB4TXFFBEAgACABkg8LIAJBgICA+AdGDQJDAAAAACABIAGUIAJB////9wdLIARBAE5zGw8LIANBAXRBgICACGpBgYCACEkEQCAAIACUIQggA0EASARAIAiMIAggBBCjBEEBRhshCAsgBEEATg0CIwBBEGsiAkMAAIA/IAiVOAIMIAIqAgwPCyADQQBIBEAgBBCjBCICRQRAIAAgAJMiACAAlQ8LIANB/////wdxIQMgAkEBRkEQdCEFCyADQf///wNLDQAgAEMAAABLlLxB/////wdxQYCAgNwAayEDCwJAQZDDAisDACADIANBgIDM+QNrIgRBgICAfHFrvrsgBEEPdkHwAXEiAkGQwQJqKwMAokQAAAAAAADwv6AiBqJBmMMCKwMAoCAGIAaiIgcgB6KiQaDDAisDACAGokGowwIrAwCgIAeiQbDDAisDACAGoiACQZjBAmorAwAgBEEXdbegoKCgIAG7oiIHvUKAgICAgIDg//8Ag0KBgICAgIDAr8AAVA0AIAdEcdXR////X0BkBEAjAEEQayICQwAAAPBDAAAAcCAFGzgCDCACKgIMQwAAAHCUDwsgB0QAAAAAAMBiwGVFDQAjAEEQayICQwAAAJBDAAAAECAFGzgCDCACKgIMQwAAABCUDwtB2NoBKwMAIAdB0NoBKwMAIgYgB6AiByAGoaEiBqJB4NoBKwMAoCAGIAaiokHo2gErAwAgBqJEAAAAAAAA8D+goCAHvSIJIAWtfEIvhiAJp0EfcUEDdEHQ2AFqKQMAfL+itiEICyAIC2UBAX8CQCAARQ0AIAFBAEgNACAAQQNxDQAgAUUEQA8LIABBACAAQQD+SAKQ8TQiAiAAIAJGGyECAkAgAUH/////B0YNACAAIAJHDQAgAUECSQ0BIAFBAWshAQsgACAB/gACABoLC4cCAQJ/IwBBEGsiBiQAIAAgAjYCBCAAQeSwATYCACAAQQhqIgIgASgCACIHNgIAIAdBBGpBAf4eAgAaIAAgASkCBDcCDCAAQRRqQQBBxAD8CwAgACAFOgBaIAAgBDoAWSAAIAM6AFggBiACKAIAIgE2AgAgAUEEakEB/h4CABogBkEEaiIDIAYiAigCAEGYAWoQ5wFBASEBIAYoAgggBi0ADyIEIATAIgRBAEgiBRtBAUYEQCAGKAIEIAMgBRstAABBwwBHIQELIARBAEgEQCAGKAIEEC8LIAIoAgAiAkEEakF//h4CAEUEQCACIAIoAgAoAggRAQALIAAgAToAWyAGQRBqJAAgAAsfAEEIEF4gABCJAyIAQdC3AzYCACAAQfC3A0EHEAIACxAAIAAoAgAEQBCZAgALIAALGQAgASACEJ0DIQEgACACNgIEIAAgATYCAAuGAgEEfyMAQRBrIgUkACABEJMDIQIjAEEQayIDJAACQCACQe////8DTQRAAkAgAkECSQRAIAAgAC0AC0GAAXEgAnI6AAsgACAALQALQf8AcToACyAAIQQMAQsgA0EIaiAAIAJBAk8EfyACQQRqQXxxIgQgBEEBayIEIARBAkYbBUEBC0EBahC5ASADKAIMGiAAIAMoAggiBDYCACAAIAAoAghBgICAgHhxIAMoAgxB/////wdxcjYCCCAAIAAoAghBgICAgHhyNgIIIAAgAjYCBAsgBCABIAIQngEgA0EANgIEIAQgAkECdGogAygCBDYCACADQRBqJAAMAQsQTQALIAVBEGokAAvkAQEGfyMAQRBrIgUkACAAKAIEIQMCfyACKAIAIAAoAgBrIgRB/////wdJBEAgBEEBdAwBC0F/CyIEQQQgBBshBCABKAIAIQcgACgCACEIIANB9wFGBH9BAAUgACgCAAsgBBDEASIGBEAgA0H3AUcEQCAAKAIAGiAAQQA2AgALIAVB9gE2AgQgACAFQQhqIAYgBUEEahBRIgMQvgMgAygCACEGIANBADYCACAGBEAgBiADKAIEEQEACyABIAAoAgAgByAIa2o2AgAgAiAAKAIAIARBfHFqNgIAIAVBEGokAA8LEEYACzsBAn8jAEEgayIFJAAgBSAENwMQIAUgAzcDCCAFIAI3AwAgACABQQMgBUEAQQAQSSEGIAVBIGokACAGC5ADAQJ/IwBBEGsiCiQAIAogADYCDAJAAkACQCADKAIAIAJHDQBBKyELIAAgCSgCYEcEQEEtIQsgCSgCZCAARw0BCyADIAJBAWo2AgAgAiALOgAADAELAkACfyAGLQALQQd2BEAgBigCBAwBCyAGLQALQf8AcQtFDQAgACAFRw0AQQAhACAIKAIAIgEgB2tBnwFKDQIgBCgCACEAIAggAUEEajYCACABIAA2AgAMAQtBfyEAIAkgCUHoAGogCkEMahCxAiAJayIGQdwASg0BIAZBAnUhBQJAAkACQCABQQhrDgMAAgABCyABIAVKDQEMAwsgAUEQRw0AIAZB2ABIDQAgAygCACIBIAJGDQIgASACa0ECSg0CIAFBAWstAABBMEcNAkEAIQAgBEEANgIAIAMgAUEBajYCACABIAVB0OoCai0AADoAAAwCCyADIAMoAgAiAEEBajYCACAAIAVB0OoCai0AADoAACAEIAQoAgBBAWo2AgBBACEADAELQQAhACAEQQA2AgALIApBEGokACAAC5UMAgZ/An0jAEFAaiIDJABBAEEB/h4CkNY0QQBKBEADQEEAQQH+JQKQ1jQaEAMQ1gFBAEEB/h4CkNY0QQBKDQALC0GE1gQtAABFBEAgA0EwahDXAQNAIAJBAnRBkNYEaiACQf//AXFBgICA+ANyvkMAAAC/kiACQRF0IgFBBHZBgICAgAdyvkMAAIAHlCABQYCAgMAASRu8IAJBEHRBgICAgHhxciIENgIAIAJBAXQiAUGQ1hRqQYD8ASAEviIHQwAAAD+UIAdDKkJMP5QgB0MTJzc9lCAHlEMAAIA/kpQQjQRDAACAP5KUIgiLQwAAgHeUQwAAgAiUQYCAgIgHIAi8IgRBAXQiBUGAgIB4cSIGIAZBgICAiAdNG0EBdkGAgIA8ar6SvCIGQQ12QYD4AXEgBkH/H3FqIAVBgICAeEsbIARBEHZBgIACcXI7AQAgAUGQ1hxqQYD8AUMAAIA/IAdDI9vZv5QQRUMAAIA/kpUgB5QiCItDAACAd5RDAACACJRBgICAiAcgCLwiBEEBdCIFQYCAgHhxIgYgBkGAgICIB00bQQF2QYCAgDxqvpK8IgZBDXZBgPgBcSAGQf8fcWogBUGAgIB4SxsgBEEQdkGAgAJxcjsBACABQZDWJGpBgPwBIAcgB4wQRUMAAIA/kpUiCItDAACAd5RDAACACJRBgICAiAcgCLwiBEEBdCIFQYCAgHhxIgYgBkGAgICIB00bQQF2QYCAgDxqvpK8IgZBDXZBgPgBcSAGQf8fcWogBUGAgIB4SxsgBEEQdkGAgAJxcjsBACABQZDWLGpBgPwBIAcQRSIHQwAAgHeUQwAAgAiUQYCAgIgHIAe8IgFBAXQiBEGAgIB4cSIFIAVBgICAiAdNG0EBdkGAgIA8ar6SvCIFQQ12QYD4AXEgBUH/H3FqIARBgICAeEsbIAFBEHZBgIACcXI7AQAgAkEBaiICQYCABEcNAAsgA0EwaiIBENcBIAEQ1wFB3LsDQQBBqJoB/AsAIAEQ1wFB5tY0QQE6AABB2NY0QQE6AABBz9Y0QQE6AABBzdY0QQE6AABBxdY0QYECOwAAQcPWNEEBOgAAQbvWNEEBOgAAQbnWNEEBOgAAQbfWNEGBAjsAAEGk1jRBAToAAEHc1jRBAToAAEG21zRBAToAAEGE1gRBAToAAAtBACECAkACQAJAAkADQCACQTRsQdy7A2oiAS0AAEUEQCACIQQMAgsgAkEBciIEQTRsQdy7A2oiAS0AAEUNASACQQJyIgRBNGxB3LsDaiIBLQAARQ0BIAJBA3IiBEE0bEHcuwNqIgEtAABFDQEgAkEEaiICQcAARw0AC0EAIQIMAQsgAUEBOgAAIARBNGxB4LsDaiECIAAoAgAiAUUEQCAAQQQ2AgBBBCEBCyABIAFBA2pBfHEiBSAAKAIEIgQbIQYCQCAEIgENACAFRQRAQQAhAUH8ugMoAgBBAE4EQEGwugMQggEhAQsCQEGe4ABBsLoDEKsEQQBIDQACQEGAuwMoAgBBCkYNAEHEugMoAgAiBUHAugMoAgBGDQBBxLoDIAVBAWo2AgAgBUEKOgAADAELENECCyABBEBBsLoDEIEBC0EAIQEMAQsgA0EANgIwIANBMGpBBCAFEIMEIgEEQCADAn8gAUEwRwRAQZYUIAFBHEcNARpBpB8MAQtBzQgLNgIkIANBgCY2AiAgAyAFuEQAAAAAAACwPqI5AyhB6PgAIANBIGoQogRBACEBDAELIAMoAjAhAQsgAiAALQAIIgA6AAogAiAAOgAJIAIgBEU6AAggAiABNgIEIAIgBjYCACAC/QwAAAAAAAAAAAAAAAAAAAAA/QsACyAC/QwAAAAAAAAAAAAAAAAAAAAA/QsAGyACQgA3ACggAUUNASABQQNxDQILQQBBAf4lApDWNBogA0FAayQAIAIPC0G8wwIoAgAQMBogA0HmLzYCCCADQf8RNgIEIANB5CY2AgBBuMMCKAIAQcvkACADEDEQAAALQbzDAigCABAwGiADQdXBADYCGCADQYESNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALCgAgAEHcijUQeQuMAwEDfyMAQRBrIgokACAKIAA6AA8CQAJAAkAgAygCACACRw0AQSshCyAAQf8BcSIMIAktABhHBEBBLSELIAktABkgDEcNAQsgAyACQQFqNgIAIAIgCzoAAAwBCwJAAn8gBi0AC0EHdgRAIAYoAgQMAQsgBi0AC0H/AHELRQ0AIAAgBUcNAEEAIQAgCCgCACIBIAdrQZ8BSg0CIAQoAgAhACAIIAFBBGo2AgAgASAANgIADAELQX8hACAJIAlBGmogCkEPahC0AiAJayIFQRdKDQECQAJAAkAgAUEIaw4DAAIAAQsgASAFSg0BDAMLIAFBEEcNACAFQRZIDQAgAygCACIBIAJGDQIgASACa0ECSg0CIAFBAWstAABBMEcNAkEAIQAgBEEANgIAIAMgAUEBajYCACABIAVB0OoCai0AADoAAAwCCyADIAMoAgAiAEEBajYCACAAIAVB0OoCai0AADoAACAEIAQoAgBBAWo2AgBBACEADAELQQAhACAEQQA2AgALIApBEGokACAACwoAIABB1Io1EHkLYwIBfwF+IwBBEGsiAiQAIAACfiABRQRAQgAMAQsgAiABrUIAIAFnIgFB0QBqEGYgAikDCEKAgICAgIDAAIVBnoABIAFrrUIwhnwhAyACKQMACzcDACAAIAM3AwggAkEQaiQACxkAIAEgAhDzAyEBIAAgAjYCBCAAIAE2AgALuQgBC38gAEUEQCABEDsPCyABQUBPBEAjA0EcakEwNgIAQQAPCwJAQbyHNS0AAEECcQRAQcCHNRBWDQELAn9BECABQQtqQXhxIAFBC0kbIQUgAEEIayIEKAIEIghBeHEhAgJAIAhBA3FFBEBBACAFQYACSQ0CGiAFQQRqIAJNBEAgBCEDIAIgBWtB8IM1KAIAQQF0TQ0CC0EADAILIAIgBGohBgJAIAIgBU8EQCACIAVrIgNBEEkNASAEIAhBAXEgBXJBAnI2AgQgBCAFaiICIANBA3I2AgQgBiAGKAIEQQFyNgIEIAIgAxD0AQwBC0GYhDUoAgAgBkYEQEGMhDUoAgAgAmoiAiAFTQ0CIAQgCEEBcSAFckECcjYCBCAEIAVqIgMgAiAFayICQQFyNgIEQYyENSACNgIAQZiENSADNgIADAELQZSENSgCACAGRgRAQYiENSgCACACaiICIAVJDQICQCACIAVrIgNBEE8EQCAEIAhBAXEgBXJBAnI2AgQgBCAFaiIHIANBAXI2AgQgAiAEaiICIAM2AgAgAiACKAIEQX5xNgIEDAELIAQgCEEBcSACckECcjYCBCACIARqIgMgAygCBEEBcjYCBEEAIQMLQZSENSAHNgIAQYiENSADNgIADAELIAYoAgQiB0ECcQ0BIAdBeHEgAmoiCSAFSQ0BIAkgBWshCwJAIAdB/wFNBEAgBigCDCIDIAYoAggiAkYEQEGAhDVBgIQ1KAIAQX4gB0EDdndxNgIADAILIAIgAzYCDCADIAI2AggMAQsgBigCGCEKAkAgBiAGKAIMIgJHBEBBkIQ1KAIAGiAGKAIIIgMgAjYCDCACIAM2AggMAQsCQCAGQRRqIgMoAgAiB0UEQCAGKAIQIgdFDQEgBkEQaiEDCwNAIAMhDCAHIgJBFGoiAygCACIHDQAgAkEQaiEDIAIoAhAiBw0ACyAMQQA2AgAMAQtBACECCyAKRQ0AAkAgBigCHCIDQQJ0QbCGNWoiBygCACAGRgRAIAcgAjYCACACDQFBhIQ1QYSENSgCAEF+IAN3cTYCAAwCCyAKQRBBFCAKKAIQIAZGG2ogAjYCACACRQ0BCyACIAo2AhggBigCECIDBEAgAiADNgIQIAMgAjYCGAsgBigCFCIDRQ0AIAIgAzYCFCADIAI2AhgLIAtBD00EQCAEIAhBAXEgCXJBAnI2AgQgBCAJaiIDIAMoAgRBAXI2AgQMAQsgBCAIQQFxIAVyQQJyNgIEIAQgBWoiAyALQQNyNgIEIAQgCWoiAiACKAIEQQFyNgIEIAMgCxD0AQsgBCEDCyADCyEDQbyHNS0AAEECcQRAQcCHNRBSGgsgAwRAIANBCGoPCyABEDsiA0UEQEEADwsgAyAAQXxBeCAAQQRrKAIAIgRBA3EbIARBeHFqIgQgASABIARLGxB7GiAAEC8LIAMLXwECfyAAQQdqQXhxIQICQANAIAJBAEHEuwP+EAIAIgAgAmoiASAATRsNASABPwBBEHRLBEAgARAdRQ0CC0EAIAAgAf5IAsS7AyAARw0ACyAADwsjA0EcakEwNgIAQX8LgwECBX8BfgJAIABCgICAgBBUBEAgACEHDAELA0AgAUEBayIBIAAgAEIKgCIHQgp+fadBMHI6AAAgAEL/////nwFWIQUgByEAIAUNAAsLIAenIgIEQANAIAFBAWsiASACIAJBCm4iA0EKbGtBMHI6AAAgAkEJSyEGIAMhAiAGDQALCyABCxoAIAAgARCOBCIAQQAgAC0AACABQf8BcUYbC88FAQh/IwBBEGsiBSQAIAACfyAFQQhqIQMgASEGAkACQEG81zQiBEG81zRHBEAgASgCACIHQczXNCgCACIBTg0BC0G81zQoAgAhBEG81zQhAwJAQbjXNCgCAEG81zRHBEACQCAERQRAQbzXNCEBA0AgASgCCCIDKAIAIAFGIQkgAyEBIAkNAAsMAQsgBCEBA0AgASIDKAIEIgENAAsLIAYoAgAiBiADKAIQTA0BCyAERQ0CIAUgAzYCDCADQQRqDAMLQbzXNCgCACIBRQ0BQbzXNCEEA0ACQCABIgMoAhAiASAGSgRAIAMiBCgCACIBDQIMAQsgASAGTg0AIANBBGohBCADKAIEIgENAQsLIAUgAzYCDCAEDAILIAEgB0gEQAJAQcDXNCgCACIGRQRAQbzXNCEBA0AgASgCCCIDKAIAIAFHIQogAyEBIAoNAAsMAQsgBiEBA0AgASIDKAIAIgENAAsLAkAgA0G81zRHBEAgByADKAIQTg0BCyAGRQRAIAVBvNc0NgIMQcDXNAwECyAFIAM2AgwgAwwDC0G81zQoAgAiAUUNAQNAAkAgASIDKAIQIgEgB0oEQCADIgQoAgAiAQ0CDAELIAEgB04NACADQQRqIQQgAygCBCIBDQELCyAFIAM2AgwgBAwCCyAFQbzXNDYCDCADQbzXNDYCACADDAELIAVBvNc0NgIMQbzXNAsiBCgCACIBBH9BAAVBIBAyIgEgAigCADYCECABQRRqIQMCQCACLAAPQQBOBEAgAyACKQIENwIAIAMgAigCDDYCCAwBCyADIAIoAgQgAigCCBBrCyABIAUoAgw2AgggAUIANwIAIAQgATYCACABIQJBuNc0KAIAKAIAIgMEQEG41zQgAzYCACAEKAIAIQILQbzXNCgCACACEKQBQcDXNEHA1zQoAgBBAWo2AgBBAQs6AAQgACABNgIAIAVBEGokAAuIAQEDf0GcEBA7IQEgABDoBCEDIAEgACgCHCICIAIoAgQRAAAiAjYCDCABIAM2AgggAUEANgIEIAEgADYCACABQRxqQQBBgBD8CwAgAUEBNgIQIAEgAyACIAMgAnBrIAJwIgJqNgIUIAEgACgCJCACazYCGEEIEDsiABCCBDYCBCAAIAE2AgAgAAuTwwcF1gF/On4gewZ9BHwjAEFAaiIuJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAABEACQCABKAJAIgJFDQACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAJBAWsOSEMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobRERERBwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ2NzU4OTo7PD0+P0BBQkQLIAEoAowBIQUgASgCkAEhAyMAQYADayIEJAACQAJAIAUoAgAiAkEOSw0AAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkBBASACdEHM+wFxRQRAAkACQAJAIAIEQCACQQFHDRggAygCAA4CAgEDCyAFKQMQItkBINkBIAMpAxAi2gF/It0BINoBflINBSAFKQMYItsBIAMpAxgi3gGBQgBSDQUgBSkDICLYASADKQMgIt8BgUIAUg0FIAUpAygi4AEgAykDKCLhAYFCAFINBSDZASABKQMQUg0FINsBIAEpAxhSDQUg2AEgASkDIFINBSDgASABKQMoUg0FAkAgACgCAA4DBQAFAAsgASgCMEEERw0GIAUoAjBBBEcNByABKAI8IQkgASgCOCEKIAEoAjQhCCADKAI8IQsgAygCOCEMIAMoAjQhDSAFKAI8IQ8gBSgCOCEOIAUoAjQhECDgASDYASDbAX4i3AF+pyICIAAoAggiB2pBAWsgB20iByAAKAIEbCIAIAdqIgcgAiACIAdKGyEHIAMoAjAiAkEERwRAIAAgB04N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y+QAIANBgAJqEDEMTgtBvMMCKAIAEDAaIANBycAANgKYAiADQevMADYClAIgA0HkJjYCkAJBuMMCKAIAQcvkACADQZACahAxDE0LQbzDAigCABAwGiADQb3AADYCGCADQbrOADYCFCADQeQmNgIQQbjDAigCAEHL5AAgA0EQahAxDEwLQbzDAigCABAwGiADQcnAADYCKCADQbnOADYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxDEsLQbzDAigCABAwGiADQd3QADYCOCADQbTOADYCNCADQeQmNgIwQbjDAigCAEHL5AAgA0EwahAxDEoLQbzDAigCABAwGiADQdfUADYCSCADQbHOADYCRCADQeQmNgJAQbjDAigCAEHL5AAgA0FAaxAxDEkLQbzDAigCABAwGiADQcg6NgJYIANBrs4ANgJUIANB5CY2AlBBuMMCKAIAQcvkACADQdAAahAxDEgLQbzDAigCABAwGiADQfE8NgJoIANBrc4ANgJkIANB5CY2AmBBuMMCKAIAQcvkACADQeAAahAxDEcLQbzDAigCABAwGiADQdQ6NgJ4IANBrM4ANgJ0IANB5CY2AnBBuMMCKAIAQcvkACADQfAAahAxDEYLQbzDAigCABAwGiADQf08NgKIASADQavOADYChAEgA0HkJjYCgAFBuMMCKAIAQcvkACADQYABahAxDEULINgBINsBfiDiAX4g2gF+pyIAQQBMDQELIAQoAtABQQAgAEECdPwLAAsgA0GgCGokAAwBC0G8wwIoAgAQMBogA0GbITYCCCADQafPADYCBCADQeQmNgIAQbjDAigCAEHL5AAgAxAxDEELDCwLIAEoAowBIQcgASgCkAEhBCABIQIjAEHQAGsiBSQAAkACQCAHKAIARQRAAkAgBygCMEEERw0AIAcoAjQiDK0i2QEgBykDECLYAUIChlINACAHNQI4ItsBINkBIAcpAxgi2gF+Ug0AIAc1Ajwg2wEgBykDICLZAX5SDQACQCABKAIwIgEgAigCAEEkbCIDQZibAWooAgBHDQAgAigCNCIIrSLbASACKQMQItwBIAGtfiADQZSbAWo0AgB/Ug0AIAI1Ajgi3QEg2wEgAikDGCLeAX5SDQAgAjUCPCDdASACKQMgItsBflINAAJAINgBINwBUg0AINoBIN4BUg0AINkBINsBUg0AIAcpAygi2wEgAikDKFINAAJAIAQpAxBCAVINACAEKQMYQgFSDQAgBCkDIEIBUg0AIAQpAyhCAVINAAJAIAAoAgAOAwcABwALINkBINoBfiDbAX6nIgEgACgCCCIDakEBayADbSIGIAAoAgRsIgMgBmoiACABIAAgAUgbIgsgA0wNBiDYAaciBkECdCENIAQoAtABKgIAIrIC/RMhkgIgBkFwcSIBQQBMDQUgASAGQQ9xIg4gBkEDcSIQayIRaiEEIAFBAWsiEkEEdkEBaiIAQf7///8BcSETIABBAXEhFgNAIAMgCGwhACACKALQASIJIAcoAtABIgpHBH8gACAJaiAKIAMgDGxqIA38CgAAIAIoAtABBSAJCyAAaiEKQQAhCUEAIQ8gEkEPRwRAA0AgCiAJQQJ0IhVqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwIAogFUHAAHJqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwIAlBIGohCSAPQQJqIg8gE0cNAAsLIBYEQCAKIAlBAnRqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwCwJAIAEgBk4NAEEAIQkgASEAIA5BBE8EQANAIAogASAJakECdGoiACCSAiAA/QACAP3mAf0LAgAgCUEEaiIJIBFHDQALIAQhACAQRQ0BCwNAIAogAEECdGoiCSCyAiAJKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwGC0G8wwIoAgAQMBogBUHU2AA2AgggBUG2zwA2AgQMOgtBvMMCKAIAEDAaIAVBuc8ANgIYIAVBtc8ANgIUDD4LQbzDAigCABAwGiAFQfTLADYCKCAFQbTPADYCJAw+C0G8wwIoAgAQMBogBUHf2QA2AjggBUGzzwA2AjQgBUHkJjYCMEG4wwIoAgBBy+QAIAVBMGoQMQxCC0G8wwIoAgAQMBogBUGbITYCSCAFQeXPADYCRCAFQeQmNgJAQbjDAigCAEHL5AAgBUFAaxAxDEELIAcoAtABIQQgAigC0AEhCSABIAZIBEAgBkEPcSEAIAQgCUcEQCABIAAgBkEDcSIOayIQaiEEIABBBEkhEQNAIAMgCGwhACAHKALQASIKIAlHBEAgACAJaiAKIAMgDGxqIA38CgAAIAIoAtABIQkLIAAgCWohD0EAIQogASEAAkAgEUUEQANAIA8gASAKakECdGoiACCSAiAA/QACAP3mAf0LAgAgCkEEaiIKIBBHDQALIAQhACAORQ0BCwNAIA8gAEECdGoiCiCyAiAKKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwCCyABIAAgBkEDcSIHayIMaiECIABBBEkhDQNAIAkgAyAIbGohBEEAIQogASEAAkAgDUUEQANAIAQgASAKakECdGoiACCSAiAA/QACAP3mAf0LAgAgCkEEaiIKIAxHDQALIAIhACAHRQ0BCwNAIAQgAEECdGoiCiCyAiAKKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwBCyAEIAlGDQAgA0EBaiG2ASALIANrQQFxBEAgAigC0AEiASAHKALQASIERwRAIAEgAyAIbGogBCADIAxsaiAN/AoAAAsgA0EBaiEDCyC2ASALRg0AA0AgAigC0AEiACAHKALQASIBRwRAIAAgAyAIbGogASADIAxsaiAN/AoAAAsgAigC0AEiACAHKALQASIBRwRAIAAgA0EBaiIEIAhsaiABIAQgDGxqIA38CgAACyADQQJqIgMgC0cNAAsLIAVB0ABqJAAMKwsgASgCjAEhAiABKAKQASEDIwBB0ABrIgQkAAJAAkACQAJAAkAgAigCAEUEQCACKQMQItkBIAEpAxBSDQEgAikDGCLYASABKQMYUg0BIAIpAyAi2gEgASkDIFINASACKQMoItsBIAEpAyhSDQEgASgCMCIFIAEoAgAiC0EkbCIHQZibAWooAgBHDQIgASgCNCIMrSLcASDZASAFrX4i3gEgB0GUmwFqKAIAIg2sf1INAiABKAI4Ig+tIt0BINgBINwBflINAiABKAI8Ig6tIt8BINoBIN0BflINAiACKAIwQQRHDQIgAjUCNCLgASDZAUIChlINAiACNQI4IuEBINgBIOABflINAiACNQI8INoBIOEBflINAiABKAJQIQYgASgCTCEJIAEoAkghCiABKAJEIQgCQCABKAJURQRAIAAoAgAiBw0BIAEoAtABIAIoAtABIAtBEGtBcU0EfyAMINgBp0EBa2wgBSDZAadsaiAPINoBp0EBa2xqIA4g2wGnQQFrbGoFINoBQgF9IN0BfiDYAUIBfSDcAX58INsBQgF9IN8Bfnwg3gEgDa1/fKcL/AoAAAsgACgCACEHCwJAAkAgBw4DAQABAAsgCCADKQMYItgBQgF9ItoBQgAg2AEg2gFaG6dsIAZqIAogAykDICLaAUIBfSLZAUIAINkBINoBWBunbGogCSADKQMoItkBQgF9ItsBQgAg2QEg2wFaG6dsaiACKAIAQSRsQZibAWooAgAgAykDECLbAUIBfSLcAUIAINsBINwBWhunbGohBSADKAI8IQ0gAygCOCEPIAMoAjQhDiABKQMoIdwBIAEpAxAh3QEgASkDICHeASABKQMYId8BIAMoAjAhtwEgACgCCCECIAAoAgQhCwJ/IAEoAgAiAEEQa0FxTQRAIABBJGxBmJsBaigCACABKAIwIN0Bp0EBa2xqIAEoAjQg3wGnQQFrbGogASgCOCDeAadBAWtsaiABKAI8INwBp0EBa2xqDAELIAE1AjQg3wFCAX1+IN0BIAE1AjB+IABBJGxBlJsBajUCAH98IAE1Ajgg3gFCAX1+fCABNQI8INwBQgF9fnynCyAFSQ0EILcBQQRHDQUgAiDZASDYASDaAX4i3AF+pyIAakEBayACbSICIAtsIgcgAiAHaiICIAAgACACShsiAE4NACDbAaciBUEATA0AIAMoAtABIQsgBUEDcSEMIAVBfHEhAiAGIAEoAtABIhBqIREgAKwh2QEgB6wh2gEgBUEQSSESA0AgCyANINoBINwBfyLbAaciAGwiE2ogDyDaASDbAcQg3AF+fSLbASDYAX8i3QGnIgNsIhZqIA4g2wEg2AEg3QF+faciB2wiFWohASAHIAhsIhggAyAKbCIaIBAgACAJbCIZampqIAZqIQNBACEHQQAhAAJAAkAgEg0AIBEgGGogGWogGmogCyAVaiATaiAWamtBEEkNAANAIAMgAEECdCITaiABIBNq/QACAP0LAgAgAEEEaiIAIAJHDQALIAIiACAFRg0BCyAAQX9zIAVqIbgBIAwEQANAIAMgAEECdCIWaiABIBZqKgIAOAIAIABBAWohACAHQQFqIgcgDEcNAAsLILgBQQNJDQADQCADIABBAnQiB2ogASAHaioCADgCACADIAdBBGoiE2ogASATaioCADgCACADIAdBCGoiE2ogASATaioCADgCACADIAdBDGoiB2ogASAHaioCADgCACAAQQRqIgAgBUcNAAsLINoBQgF8ItoBINkBUg0ACwsgBEHQAGokAAwFC0G8wwIoAgAQMBogBEGbITYCSCAEQcvQADYCRAw/C0G8wwIoAgAQMBogBEG5zwA2AjggBEHxzwA2AjQMPwtBvMMCKAIAEDAaIARBxNkANgIoIARB8s8ANgIkDD8LQbzDAigCABAwGiAEQYzMADYCCCAEQZrQADYCBAw2C0G8wwIoAgAQMBogBEGJ0QA2AhggBEGc0AA2AhQMPgsMKgsgACABKAKMASABEPUCDCkLIAAgASgCjAEgARD1AgwoCyABKAKMASEEIAEoApABIQIjAEEQayIFJAACQAJAAkACQAJAAkAgBCgCACIDQQZrQQlJDQAgAw4EAgEAAAQLAkAgACgCAA4DAwADAAsgAikDICLbAUIAVw0CIAIpAxgi3AFCAFcNAiACKQMQIt0BQgBXDQIgASgCPCEHIAEoAjghBiABKAI0IQkgAigCOCEKIAIoAjQhCCAEKAI8IQsgBCgCOCEMIAQoAjQhDSADQSRsQaCbAWooAgAhAyACKAIwIQ8gBCgCECEOA0AgByDaAaciAGwhECAAIAtsIREgACAKbCESQgAh2AEDQCAGINgBpyIAbCETIAAgDGwhFiAAIAhsIQBCACHZAQNAIAQoAtABIAIoAtABIA8g2QGnIhVsaiAAaiASaigCACANbGogFmogEWogASgC0AEgCSAVbGogE2ogEGogDiADEQUAINkBQgF8ItkBIN0BUg0ACyDYAUIBfCLYASDcAVINAAsg2gFCAXwi2gEg2wFSDQALDAILAkAgACgCAA4DAgACAAsgAikDICLbAUIAVw0BIAIpAxgi3AFCAFcNASACKQMQIt0BQgBXDQEgBCgCECIAQQBMDQEgASgCPCEGIAEoAjghCSABKAI0IQogAigCOCEIIAIoAjQhCyAEKAI8IQwgBCgCOCENIAQoAjQhDyACKAIwIQ4gASgC0AEhECAEKALQASERIAIoAtABIRIgAEF8cSETIABBA3EhBCAAQQRJIRYD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JAACQCAEKAIARQRAIAAgBCABQwAAAAAQ7QQgAkEQaiQADAELQbzDAigCABAwGiACQZshNgIIIAJBpdQANgIEDCoLDCMLIAEoAowBIQsgASgCkAEhDCABIQMjAEEQayINJAACQCALKAIARQRAAkACQCAAKAIADgMBAAEACyAAKAIIIQEgACgCBCECIAwEfiAMKQMYBUIBCyHaASABIAspAyggCykDICALKQMYfn6nIgRqQQFrIAFtIgEgAmwiBiABIAZqIgEgBCABIARIGyIJTg0AIAsoAhAiB0FwcSIBIAdBD3EiDyAHQQNxIgprIg5qIQQgACgCECAHQRBqIAJsQQJ0aiIFIAdBAnQiGmohGSAHQXxxIQIgB0EBayEQIAFBAWsiEUEEdkEBaiIAQf7///8BcSESIABBAXEhEyADKgJEIrQC/RMhkgIgCawh2QEgBqwh2AEgB0EISSEWA0AgAygCNCG8ASADKALQASEXIAsoAjQhACALKALQASEGIAwEfyAMKALQASAMKAI0INgBINoBgadsagVBAAshCSDYAachFQJAIAdBAEwiGA0AIAYgACAVbGohCEEAIQZBACEAAkAgFg0AIAUgCGtBEEkNAANAIAUgAEECdCIbaiAIIBtq/QACAP0LAgAgAEEEaiIAIAJHDQALIAcgAiIARg0BCyAQIABrIbsBIAoEQANAIAUgAEECdCIcaiAIIBxqKgIAOAIAIABBAWohACAGQQFqIgYgCkcNAAsLILsBQQNJDQADQCAFIABBAnQiBmogBiAIaioCADgCACAFIAZBBGoiG2ogCCAbaioCADgCACAFIAZBCGoiG2ogCCAbaioCADgCACAFIAZBDGoiBmogBiAIaioCADgCACAAQQRqIgAgB0cNAAsLAkAgAUEATCIbDQBBACEIQQAhBiARQQ9HBEADQCAFIAhBAnQiHGoiACCSAiAA/QAAAP3mAf0LAAAgACCSAiAA/QAAEP3mAf0LABAgACCSAiAA/QAAIP3mAf0LACAgACCSAiAA/QAAMP3mAf0LADAgBSAcQcAAcmoiACCSAiAA/QAAAP3mAf0LAAAgACCSAiAA/QAAEP3mAf0LABAgACCSAiAA/QAAIP3mAf0LACAgACCSAiAA/QAAMP3mAf0LADAgCEEgaiEIIAZBAmoiBiASRw0ACwsgE0UNACAFIAhBAnRq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swIgtAJeGyK0AiCyAiCyAiC0Al0bOAIAIABBAXIhAAsgwwEgDUYNAANAIAMgAEECdCILaiABIAtqKgIAIrQCILMCILMCILQCXhsitAIgsgIgsgIgtAJdGzgCACADIAtBBGoiC2ogASALaioCACK0AiCzAiCzAiC0Al4bIrQCILICILICILQCXRs4AgAgAEECaiIAIAdHDQALCyAGQQFqIQYgBSAKaiIFIAxIDQALCyAEQTBqJAAMAgtBvMMCKAIAEDAaIARBttEANgIIIARBr9cANgIEDCkLQbzDAigCABAwGiAEQd3QADYCGCAEQa7XADYCFAwxCwwdCyABKAKMASECIAEoApABIQMjAEGQAWsiBCQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAigCAA4CAQALCyADKAIADQIgASgCAA0DIAIoAjBBAkcNBCADKAIwQQRHDQUgAikDICLfASACKQMQItwBfiLiASACKQMYIuMBfqchByADKQMYIeEBIAMpAxAh4AECQAJAIAAoAgAOAwABAwELIAMoAjQhCiACKAI4IQYgAigCNCEJIAAoAhBBACAAKAIM/AsAIAAoAhAhBQJAIN8BQgBXDQAg4wFCAFcNACDcAUIAVw0AIN8BQgFSINwBQghUciEIINwBQgODIeQBINwBQniDIdoBINwBQgGGIeUBIAmtIeYBIAatIecBIAIoAtABIgutIegBIAWtIekBA0Ag2QEg5wF+IOgBfCHqASDZAUIBhiDpAXwh6wEgCyAGINkBp2xqIQxCACHdAQNAIAwgCSDdAadsaiEAIAUg3QEg4gF+p0EBdGohAkIAId4BQgAh2wFCACHYAQJAIAgg6wEg3QEg5QF+fKcg6gEg3QEg5gF+fKdrQRBJckUEQANAIAIg2QEg2wF8p0EBdGogACDbAadBAXRq/QABAP0LAQAg2wFCCHwi2wEg2gFSDQALINoBItgBINwBUQ0BCyDcASDYAUJ/hXwhiwIg5AFCAFIEQANAIAIg2AEg3wF+INkBfKdBAXRqIAAg2AGnQQF0ai8BADsBACDYAUIBfCHYASDeAUIBfCLeASDkAVINAAsLIIsCQgNUDQADQCACINgBIN8BfiDZAXynQQF0aiAAINgBp0EBdGovAQA7AQAgAiDYAUIBfCLbASDfAX4g2QF8p0EBdGogACDbAadB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ASAANQIwfiAHQSRsQZSbAWo1AgB/fCAAKAI4IgetINgBQgF9fnwgADUCPCAAKQMoQgF9fnynCyIAQQBMDQAgASkDGCLdAUIAVw0AIAEpAxAi2wFCAFcNAAJAAkAgA0ECRwRAIAAgBGohCSABKALQASEAINsBIN0BfqchCiAIIAtssiGyAiDbAachBiAIQQBMDQEgC0EATA0CIAutItgBQv7///8PgyHiASDYAUIBgyHjASDYAUIBfSHkASAIrSHlASADQQFrIQsDQEIAId8BA0AgACDfAaciASAGbEECdGohECABIA5sIA9rrCHmAUIAIeABA0AgECDgAaciCEECdGohAQJAAkACQCADDgIBAAILIAFBADYCACAIIA1sIAxrrCHhAUIAIdoBA0ACQCDaASDmAXwi2AFCAFMNACDeASDYAUL/////D4NXDQAgBCACINgBp2xqIQhCACHYAUIAIdwBIOQBQgBSBEADQAJAINgBIOEBfCLnAUIAUw0AINkBIOcBQv////8Pg1cNACABIAgg5wGnQQJ0aioCACABKgIAkjgCAAsCQCDYAUIBhCDhAXwi5wFCAFMNACDZASDnAUL/////D4NXDQAgASAIIOcBp0ECdGoqAgAgASoCAJI4AgALINgBQgJ8IdgBINwBQgJ8ItwBIOIBUg0ACwsg4wFQDQAg2AEg4QF8ItgBQgBTDQAg2QEg2AFC/////w+DVw0AIAEgCCDYAadBAnRqKgIAIAEqAgCSOAIACyDaAUIBfCLaASDlAVINAAsMAQsgAUH///97NgIAIAggDWwgDGusIeEBQgAh2gEDQAJAINoBIOYBfCLYAUIAUw0AIN4BINgBQv////8Pg1cNACAEIAIg2AGnbGohCEIAIdgBQgAh3AEg5AFCAFIEQANAAkAg2AEg4QF8IucBQgBTDQAg2QEg5wFC/////w+DVw0AIAgg5wGnQQJ0aioCACKzAiABKgIAXkUNACABILMCOAIACwJAINgBQgGEIOEBfCLnAUIAUw0AINkBIOcBQv////8Pg1cNACAIIOcBp0ECdGoqAgAiswIgASoCAF5FDQAgASCzAjgCAAsg2AFCAnwh2AEg3AFCAnwi3AEg4gFSDQALCyDjAVANACDYASDhAXwi2AFCAFMNACDZASDYAUL/////D4NXDQAgCCDYAadBAnRqKgIAIrMC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IAVBfnEhCQNAIAcgASgC0AEgASgCNCAAbGogAigC0AEgAigCNCAAbGogAxEFACAHIAEoAtABIABBAXIiCiABKAI0bGogAigC0AEgAigCNCAKbGogAxEFACAAQQJqIQAgBkECaiIGIAlHDQALCyAFQQFxRQ0AIAcgASgC0AEgASgCNCAAbGogAigC0AEgAigCNCAAbGogAxEFAAsgBEEgaiQADAILQbzDAigCABAwGiAEQZshNgIYIARB+eoANgIUDCALQbzDAigCABAwGiAEQbnPADYCCCAEQdrqADYCBAwWCwwLCyABKAKMASECIAEoApABIQMgASgCRCEFIwBBEGsiBCQAAkAgAigCAEUEQAJAAkAgACgCAA4DAQABAAsgAikDKCACKQMgIAIpAxh+fqciB0EATA0AIAIoAhAhBkEAIQADQCAGIAEoAtABIAEoAjQgAGxqIAIoAtABIAIoAjQgAGxqIAMoAtABIAMoAjQgAGxqIAURBgAgAEEBaiIAIAdHDQALCyAEQRBqJAAMAQtBvMMCKAIAEDAaIARBmyE2AgggBEGp6wA2AgQMFQsMCgsCQCAAKAIADgMKAAoACyABIAEoAowBIAEoAkQRAgAMCQsCQCAAKAIADgMJAAkACyABIAEoAowBIAEoApABIAEoAkQRBQAMCAsCQCAAKAIADgMIAAgACyABIAEoAowBIAEoApABIAEoApQBIAEoAkQRBgAMBwsgASgCjAEhAgJAAkAgACgCAA4DAQABAAsgASACIAAoAgQgACgCCCABKAJMIAEoAkQRCwALDAYLIAEoAowBIQIgASgCkAEhBAJAAkAgACgCAA4DAQABAAsgASACIAQgACgCBCAAKAIIIAEoAkwgASgCRBEMAAsMBQsgASgCjAEhAiABKAKQASEEIAEoApQBIQMCQAJAIAAoAgAOAwEAAQALIAEgAiAEIAMgACgCBCAAKAIIIAEoAkwgASgCRBEQAAsMBAsgACEEIAEoAowBIQkgASgCkAEhCiMAQeAAayIFJAACQAJAAn0CQCAJKAIARQRAAkAgCSgCMEEERw0AIAk1AjQi2QEgCSkDECLYAUIChlINACAJNQI4ItsBINkBIAkpAxgi2gF+Ug0AIAk1Ajwg2wEgCSkDICLZAX5SDQACQCAKKAIwIgAgCigCAEEkbCICQZibAWooAgBHDQAgCjUCNCLbASAKKQMQItwBIACtfiACQZSbAWo0AgB/Ug0AIAo1Ajgi3QEg2wEgCikDGCLeAX5SDQAgCjUCPCDdASAKKQMgItsBflINAAJAIAEpAxBCAVINACABKQMYQgFSDQAgASkDIEIBUg0AIAEpAyhCAVINAAJAINgBINwBUg0AINoBIN4BUg0AINkBINsBUg0AIAkpAygi2wEgCikDKFINACAEKAIIIgAg2AGnIgZBAnQiE0EEamwiAyAEKAIMTQRAINkBINoBfiDbAX6nIQIgBCgCECEHIAQoAgQhCAJAAkACQCAEKAIADgMAAgECCyAIDQogB0EAIAP8CwAMCgsgCA0JIAEoAtABIQlDAAAAACAAQQBMDQgaIABBA3EhBEEAIQMgAEEESQRAQQAhAAwICyAAQXxxIQpBACEAQQAhBgNAILgCIAcgAEECdCIBaioCALugIAcgAUEEcmoqAgC7oCAHIAFBCHJqKgIAu6AgByABQQxyaioCALugIbgCIABBBGohACAGQQRqIgYgCkcNAAsMBwsgACACakEBayAAbSIBIAhsIg0gASANaiIBIAIgASACSBsiFk4NCCAGQXBxIgIgBkEPcSIVIAZBA3EiDGsiGGohAyAAQQJ0IhogCEECdCIAQQRqIAZsaiEZIAZBfHEhASAGQX5xIRQgBkEBcSEXIAZBAWshDiAAIAdqIRAgAkEBayIbQQR2QQFqIgBB/v///wFxIRwgAEEBcSEdIAYgCGxBAnQhHwNAIAQoAhAiHiAaaiAfaiEHIAooAjQhIyAKKALQASERAkAgBkEATCIlBEBEAAAAAAAAAAAhuAIMAQsgCSgC0AEgCSgCNCANbGohC0MAAID/IbICQQAhD0EAIQBBACESIA5BA08EQANAILICIAsgAEECdCIIaioCACKzAiCyAiCzAl4bIrICIAsgCEEEcmoqAgAiswIgsgIgswJeGyKyAiALIAhBCHJqKgIAIrMCILICILMCXhsisgIgCyAIQQxyaioCACKzAiCyAiCzAl4bIbICIABBBGohACASQQRqIhIgAUcNAAsLIAwEQANAILICIAsgAEECdGoqAgAiswIgsgIgswJeGyGyAiAAQQFqIQAgD0EBaiIPIAxHDQALC0QAAAAAAAAAACG4AkEAIQBBACEIIA4EQANAQwAAAAAhswICQCALIABBAnQi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QQFqIQAgA0EBaiIDIARHDQALCyC4ArYLIbICIAlDAACAvyACspUgsgKUOAIACyAFQeAAaiQADAALDAMLIAEoAowBIQkgASgCkAEhCiABKAKUASECIAEhAyMAQeAAayIFJAACQCAJKAIARQRAAkAgASgCMCIBIAMoAgBBJGwiBEGYmwFqKAIARw0AIAM1AjQi2QEgAykDECLYASABrX4gBEGUmwFqNAIAf1INACADNQI4ItsBINkBIAMpAxgi2gF+Ug0AIAM1Ajwg2wEgAykDICLZAX5SDQACQCAJKAIwQQRHDQAgCTUCNCLdASAJKQMQItsBQgKGUg0AIAk1Ajgi3gEg3QEgCSkDGCLcAX5SDQAgCTUCPCDeASAJKQMgIt0BflINAAJAIAooAjAiASAKKAIAQSRsIgRBmJsBaigCAEcNACAKNQI0It4BIAopAxAi3wEgAa1+IARBlJsBajQCAH9SDQAgCjUCOCLgASDeASAKKQMYIuEBflINACAKNQI8IOABIAopAyAi3gF+Ug0AAkAgAigCMCIBIAIoAgBBJGwiBEGYmwFqKAIARw0AIAI1AjQi4AEgAikDECABrX4gBEGUmwFqNAIAf1INACACNQI4IuIBIAIpAxgg4AF+Ug0AIAI1AjwgAikDICDiAX5SDQACQCDbASDfAVINACDcASDhAVINACDdASDeAVINACDZASDdAVINACDaASDcAVINACDYASDbAVINACAJKQMoItsBIAopAyhSDQAg2wEgAykDKFINAAJAAkAgACgCAA4DAQABAAsg2QEg2gF+INsBfiLZASAANAIIItoBfEIBfSDaAX8i2wEgADQCBH4i2gEg2gEg2wF8ItsBINkBINkBINsBVRsi3AFZDQAgAigC0AEhGCDYAaciBkFwcSIBIAZBD3EiDSAGQQNxIgxrIg9qIQQg2AFCfoMh3QEg2AFCAYMh3gEgBkF8cSECIAZBAnQhDiABQQFrIhBBBHZBAWoiAEH+////AXEhESAAQQFxIRIg2QG0IbUCIAZBAWtBA0khGgNAIAkoAtABINoBpyITIAkoAjRsaiEAIAMoAjQgE2whFkMAAID/IbICAkAgBkEATCIZDQBBACEIQQAhB0EAIRUgGkUEQANAILICIAAgB0ECdCILaioCACKzAiCyAiCzAl4bIrICIAAgC0EEcmoqAgAiswIgsgIgswJeGyKyAiAAIAtBCHJqKgIAIrMCILICILMCXhsisgIgACALQQxyaioCACKzAiCyAiCzAl4bIbICIAdBBGohByAVQQRqIhUgAkcNAAsLIAxFDQADQCCyAiAAIAdBAnRqKgIAIrMCILICILMCXhshsgIgB0EBaiEHIAhBAWoiCCAMRw0ACwsgCigCNCEUIAooAtABIRUgAygC0AEiFyAWaiEHAkAg2AFCAFcEQEQAAAAAAAAAACG4AgwBC0QAAAAAAAAAACG4AkIAIdkBQgAh2wEg2AFCAVIEQANAQwAAAAAhswICQCAAINkBpyIIQQJ0IgtqKgIAIrQCQwAAgP9bBEBDAAAAACG0AgwBCyC4AiC0AiCyApMQRSK0ArugIbgCCyAHIAtqILQCOAIAIAAgCEEBckECdCIIaioCACK0AkMAAID/XARAILgCILQCILICkxBFIrMCu6AhuAILIAcgCGogswI4AgAg2QFCAnwh2QEg2wFCAnwi2wEg3QFSDQALCyDeAVANAEMAAAAAIbMCIAAg2QGnQQJ0IghqKgIAIrQCQwAAgP9cBEAguAIgtAIgsgKTEEUiswK7oCG4AgsgByAIaiCzAjgCAAtEoY92////7z8guAKjtiGyAgJAIAFBAEwiGw0AILIC/RMhkgJBACEAQQAhCCAQQQ9HBEADQCAHIABBAnQiHGoiCyCSAiAL/QAAAP3mAf0LAAAgCyCSAiAL/QAAEP3mAf0LABAgCyCSAiAL/QAAIP3mAf0LACAgCyCSAiAL/QAAMP3mAf0LADAgByAcQcAAcmoiCyCSAiAL/QAAAP3mAf0LAAAgCyCSAiAL/QAAEP3mAf0LABAgCyCSAiAL/QAAIP3mAf0LACAgCyCSAiAL/QAAMP3mAf0LADAgAEEgaiEAIAhBAmoiCCARRw0ACwsgEkUNACAHIABBAnRqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwCwJAIAEgBk4iHA0AIAEhACANQQRPBEAgsgL9EyGSAkEAIQADQCAHIAAgAWpBAnRqIgggCP0AAgAgkgL95gH9CwIAIABBBGoiACAPRw0ACyAEIQAgDEUNAQsDQCAHIABBAnRqIgggCCoCACCyApQ4AgAgAEEBaiIAIAZHDQALCwJAIBkNACATIBRsIRNBACEAAkAgBkEETwRAA0AgByAAQQJ0aiIIIAj9AAIA/QxfcIkwX3CJMF9wiTBfcIkw/eQB/QsCACAAQQRqIgAgAkcNAAsgBiACIgBGDQELA0AgByAAQQJ0aiIIIAgqAgBDX3CJMJI4AgAgAEEBaiIAIAZHDQALCyATIBVqIQtBACEIQQAhAAJAIAZBCEkNACALIA4gF2ogFmpJIA4gFWogE2ogB0txDQADQCAHIABBAnQiE2oiFiAW/QACACALIBNq/QACAP3lAf0LAgAgAEEEaiIAIAJHDQALIAYgAiIARg0BCyAAQX9zIAZqIdYBIAwEQANAIAcgAEECdCIWaiIVIBUqAgAgCyAWaioCAJM4AgAgAEEBaiEAIAhBAWoiCCAMRw0ACwsg1gFBA0kNAANAIAcgAEECdCIIaiITIBMqAgAgCCALaioCAJM4AgAgByAIQQRqIhNqIhYgFioCACALIBNqKgIAkzgCACAHIAhBCGoiE2oiFiAWKgIAIAsgE2oqAgCTOAIAIAcgCEEMaiIIaiITIBMqAgAgCCALaioCAJM4AgAgAEEEaiIAIAZHDQALCyAYKgIAILUClSGyAgJAIBsNACCyAv0TIZICQQAhAEEAIQggEEEPRwRAA0AgByAAQQJ0IhNqIgsgkgIgC/0AAAD95gH9CwAAIAsgkgIgC/0AABD95gH9CwAQIAsgkgIgC/0AACD95gH9CwAgIAsgkgIgC/0AADD95gH9CwAwIAcgE0HAAHJqIgsgkgIgC/0AAAD95gH9CwAAIAsgkgIgC/0AABD95gH9CwAQIAsgkgIgC/0AACD95gH9CwAgIAsgkgIgC/0AADD95gH9CwAwIABBIGohACAIQQJqIgggEUcNAAsLIBJFDQAgByAAQQJ0aiIAIJICIAD9AAAA/eYB/QsAACAAIJICIAD9AAAQ/eYB/QsAECAAIJICIAD9AAAg/eYB/QsAICAAIJICIAD9AAAw/eYB/QsAMAsCQCAcDQAgASEAIA1BBE8EQCCyAv0TIZICQQAhAANAIAcgACABakECdGoiCCCSAiAI/QACAP3mAf0LAgAgAEEEaiIAIA9HDQALIAQhACAMRQ0BCwNAIAcgAEECdGoiCCCyAiAIKgIAlDgCACAAQQFqIgAgBkcNAAsLINoBQgF8ItoBINwBUg0ACwsgBUHgAGokAAwGC0G8wwIoAgAQMBogBUHYzgA2AgggBUGa7QA2AgQgBUHkJjYCAEG4wwIoAgBBy+QAIAUQMQwcC0G8wwIoAgAQMBogBUGr2QA2AhggBUGZ7QA2AhQgBUHkJjYCEEG4wwIoAgBBy+QAIAVBEGoQMQwbC0G8wwIoAgAQMBogBUG72AA2AiggBUGY7QA2AiQgBUHkJjYCIEG4wwIoAgBBy+QAIAVBIGoQMQwaC0G8wwIoAgAQMBogBUHf2QA2AjggBUGX7QA2AjQgBUHkJjYCMEG4wwIoAgBBy+QAIAVBMGoQMQwZC0G8wwIoAgAQMBogBUH0ywA2AkggBUGW7QA2AkQgBUHkJjYCQEG4wwIoAgBBy+QAIAVBQGsQMQwYC0G8wwIoAgAQMBogBUGbITYCWCAFQfftADYCVCAFQeQmNgJQQbjDAigCAEHL5AAgBUHQAGoQMQwXCwwCC0G8wwIoAgAQMBogLkGbITYCGCAuQcvwADYCFCAuQeQmNgIQQbjDAigCAEHL5AAgLkEQahAxDBULIAAgASgCjAEgARD1AgsgLkFAayQADwtBvMMCKAIAEDAaIC5BxRA2AgggLkH/7QA2AgQgLkHkJjYCAEG4wwIoAgBBy+QAIC4QMQwSC0G8wwIoAgAQMBogLkGpPjYCKCAuQebvADYCJCAuQeQmNgIgQbjDAigCAEHL5AAgLkEgahAxDBELQbzDAigCABAwGiAuQak+NgI4IC5B8e8ANgI0IC5B5CY2AjBBuMMCKAIAQcvkACAuQTBqEDEMEAsgAkHkJjYCIEG4wwIoAgBBy+QAIAJBIGoQMQwPCyACQeQmNgIQQbjDAigCAEHL5AAgAkEQahAxDA4LIAJB5CY2AgBBuMMCKAIAQcvkACACEDEMDQsgAkHkJjYCMEG4wwIoAgBBy+QAIAJBMGoQMQwMCyACQeQmNgJAQbjDAigCAEHL5AAgAkFAaxAxDAsLIAVB5CY2AgBBuMMCKAIAQcvkACAFEDEMCgsgBEHkJjYCAEG4wwIoAgBBy+QAIAQQMQwJCyADQeQmNgIAQbjDAigCAEHL5AAgAxAxDAgLIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEMBwsgA0HkJjYCIEG4wwIoAgBBy+QAIANBIGoQMQwGCyAFQeQmNgIQQbjDAigCAEHL5AAgBUEQahAxDAULIAVB5CY2AiBBuMMCKAIAQcvkACAFQSBqEDEMBAsgBEHkJjYCQEG4wwIoAgBBy+QAIARBQGsQMQwDCyAEQeQmNgIwQbjDAigCAEHL5AAgBEEwahAxDAILIARB5CY2AiBBuMMCKAIAQcvkACAEQSBqEDEMAQsgBEHkJjYCEEG4wwIoAgBBy+QAIARBEGoQMQsQAAALiAEBAX8gAC0AC0EHdgR/IAAoAghB/////wdxQQFrBUEKCyIDIAJPBEACfyAALQALQQd2BEAgACgCAAwBCyAACyIDIAEgAvwKAAAgACADIAIQnAMPCyAAIAMgAiADawJ/IAAtAAtBB3YEQCAAKAIEDAELIAAtAAtB/wBxCyIAQQAgACACIAEQzAELiAMBBX8jAEEQayIIJAAgAiABQX9zQe////8Hak0EQAJ/IAAtAAtBB3YEQCAAKAIADAELIAALIQogCEEEaiIJIAAgAUHn////A0kEfyAIIAFBAXQ2AgwgCCABIAJqNgIEIwBBEGsiAiQAIAkoAgAgCEEMaiILKAIASSEMIAJBEGokACALIAkgDBsoAgAiAkELTwR/IAJBEGpBcHEiAiACQQFrIgIgAkELRhsFQQoLQQFqBUHv////BwsQwwEgCCgCBCECIAgoAggaIAQEQCACIAogBBB3CyAGBEAgAiAEaiAHIAYQdwsgAyAEIAVqIglrIQcgAyAJRwRAIAIgBGogBmogBCAKaiAFaiAHEHcLIAFBAWoiAUELRwRAIAAgCiABEPEBCyAAIAI2AgAgACAAKAIIQYCAgIB4cSAIKAIIQf////8HcXI2AgggACAAKAIIQYCAgIB4cjYCCCAAIAQgBmogB2oiADYCBCAIQQA6AAwgACACaiAILQAMOgAAIAhBEGokAA8LEE0ACwsAIAQgAjYCAEEDC+kCAgV/AX4CfyMAQTBrIgMkAAJAAkAgAikDEEIBUg0AIAIpAxhCAVINACACKQMgQgFSDQAgAikDKEIBUg0AIAEoAjAgASgCACIEQSRsQZibAWooAgBHDQEgATUCOCIIIAEpAxggATUCNH5SDQEgATUCPCABKQMgIAh+Ug0BAn8CQCABKAKIAQ0AIAIoAogBDQBBAAwBC0EBCyEHIAAgBCABKAIMIAFBEGpBAEEAEEkiBEEaNgJAIAcEQCAAIAQoAgAgBCgCDCAEQRBqQQBBABBJIQULIAQgATYCjAEgBCAFNgKIASAEIAI2ApABIANBMGokACAEDAILQbzDAigCABAwGiADQYLXADYCKCADQcogNgIkIANB5CY2AiBBuMMCKAIAQcvkACADQSBqEDEQAAALQbzDAigCABAwGiADQfLXADYCGCADQcsgNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALC3gBAn8jAEEQayIDJAAgA0EMaiIEIAEoAhwiATYCACABQQRqQQH+HgIAGiACIAQQvwEiASABKAIAKAIQEQAANgIAIAAgASABKAIAKAIUEQIAIAQoAgAiAEEEakF//h4CAEUEQCAAIAAoAgAoAggRAQALIANBEGokAAtwAQJ/IwBBEGsiAiQAIAJBDGoiAyAAKAIcIgA2AgAgAEEEakEB/h4CABogAxBsIgBB0OoCQerqAiABIAAoAgAoAjARCAAaIAMoAgAiAEEEakF//h4CAEUEQCAAIAAoAgAoAggRAQALIAJBEGokACABC3gBAn8jAEEQayIDJAAgA0EMaiIEIAEoAhwiATYCACABQQRqQQH+HgIAGiACIAQQwQEiASABKAIAKAIQEQAAOgAAIAAgASABKAIAKAIUEQIAIAQoAgAiAEEEakF//h4CAEUEQCAAIAAoAgAoAggRAQALIANBEGokAAsLACAAEJoEIAAQLwspAAJAIAAoAgBBAE4NACAAQf////8H/h4CAEGBgICAeEYNACAAEI4BCwtIAQJ/AkAgAigCTEEASARAIAAgASACEM4CIQAMAQsgAhCCASEEIAAgASACEM4CIQAgBEUNACACEIEBCyAAIAFGBEAgAQ8LIAALjwICAX8CfCAAQQNxBH9BZAVEAAAAAAAAAAAQ1gEjBkUEQAJ/EAMhBUEAQQAgAP5IApDxNBoCQBADIgQgBSACoCICZA0AAn8DQEEAIABBACAAQQD+SAKQ8TQiAyAAIANGG0UNARogBBDWASABIAD+EAIARgRAQQBBACAA/kgCkPE0GhADIgQgAmQNAwwBCwtBegsMAQtBACAAQQD+SAKQ8TQaQbd/Cw8LIAJEAAAAAAAA8H9iIQNBekG3f0EAIAAgAQJ+IAJEAAAAAABAj0CiRAAAAAAAQI9AoiICmUQAAAAAAADgQ2MEQCACsAwBC0KAgICAgICAgIB/C0J/IAMb/gECACIAQQJGGyAAQQFGGwsLJQACQCMFBEBBjPE0/hACAA0BENoGCw8LQYzxNP4QAgAQJxAmAAuyAQMCfAF/AX4jASIDLQAIRQRAIAMQKDoACSADQQE6AAgLIAACfgJ8IwEtAAkEQBADDAELIwNBHGpBHDYCAA8LIgFEAAAAAABAj0CjIgKZRAAAAAAAAOBDYwRAIAKwDAELQoCAgICAgICAgH8LIgQ3AwAgAAJ/IAEgBELoB365oUQAAAAAAECPQKJEAAAAAABAj0CiIgGZRAAAAAAAAOBBYwRAIAGqDAELQYCAgIB4CzYCCAvKBAICfwJ8IwBBEGshBCACKwMAIQYCfwJAIAErAwAiByAAKwMAZEUEQEEAIAYgB2RFDQIaIAQgAf0AAwD9CwMAIAEgAigCCDYCCCABIAIpAwA3AwAgAiAEKAIINgIIIAIgBCkDADcDAEEBIAErAwAgACsDAGRFDQIaIAQgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASAEKAIINgIIIAEgBCkDADcDAAwBCyAGIAdkBEAgBCAA/QADAP0LAwAgACACKAIINgIIIAAgAikDADcDACACIAQoAgg2AgggAiAEKQMANwMAQQEMAgsgBCAA/QADAP0LAwAgACABKAIINgIIIAAgASkDADcDACABIAQoAgg2AgggASAEKQMANwMAQQEgAisDACABKwMAZEUNARogBCAB/QADAP0LAwAgASACKAIINgIIIAEgAikDADcDACACIAQoAgg2AgggAiAEKQMANwMAC0ECCyEFIAMrAwAgAisDAGQEfyAEIAL9AAMA/QsDACACIAMoAgg2AgggAiADKQMANwMAIAMgBCgCCDYCCCADIAQpAwA3AwAgAisDACABKwMAZEUEQCAFQQFqDwsgBCAB/QADAP0LAwAgASACKAIINgIIIAEgAikDADcDACACIAQoAgg2AgggAiAEKQMANwMAIAErAwAgACsDAGRFBEAgBUECag8LIAQgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASAEKAIINgIIIAEgBCkDADcDACAFQQNqBSAFCwunAwELfwJAAkAgACgCBCIDIAAoAgBHBEAgAyECDAELIAAoAggiBCAAKAIMIgJJBEAgBCACIARrQQJ1QQFqQQJtQQJ0IgZqIAQgA2siBWsiAiADIAX8CgAAIAAgAjYCBCAAIAAoAgggBmo2AggMAQtBASACIANrQQF1IAIgA0YbIgVBgICAgARPDQEgBUECdCICEDIiByACaiEMIAcgBUEDaiIIQXxxaiICIQkCQCADIARGDQAgAiAEIANrIgRBfHFqIQkgAiEGIAMhBQJAIARBBGsiBEEcSQ0AIAhBfHEgB2ogA2tBEEkNACADIARBAnZBAWoiCEH8////B3EiCkECdCIGaiEFIAIgBmohBgNAIAIgC0ECdCIEaiADIARq/QACAP0LAgAgC0EEaiILIApHDQALIAggCkYNAQsDQCAGIAUoAgA2AgAgBUEEaiEFIAZBBGoiBiAJRw0ACwsgACAMNgIMIAAgCTYCCCAAIAI2AgQgACAHNgIAIANFDQAgAxAvIAAoAgQhAgsgAkEEayABKAIANgIAIAAgACgCBEEEazYCBA8LEEcAC78VARh/IAAoAgAhEyAAKAIEIgMoAgghAAJAIAEoAhgiCyADKAIETQRAIAtBA3QhBCALQQJ0IQIMAQsgAARAIAAQLwsgAygCDCIABEAgABAvCyALQQJ0IgIQOyEAIAMgCzYCBCADIAA2AgggAyALQQN0IgQQOzYCDAsgAEEAIAL8CwAgAygCDEEAIAT8CwAgAyATNgIAQQAhACMAQfAAayIFJAAgAygCHCENIAMoAhghEiABIgsoAgQiCEEASgRAA0ACQCALKAIMIABBAnRqKAIAIgQoAsgBIgFFDQAgBSADKQIENwNoIAVB6ABqIAEQYiEBIAMoAgwgAUEDdGoiASABKAIEQQFqNgIEIAQoAggNACAEKALQAUUNACADIARBARB4CwJAIAQoAowBIgJFDQAgBSADKQIENwNgIAVB4ABqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAAkAgAigCyAFFDQAgAigCCA0AIAIoAtABRQ0AIAMgAkEBEHgLIAQoApABIgJFDQAgBSADKQIENwNYIAVB2ABqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAAkAgAigCyAFFDQAgAigCCA0AIAIoAtABRQ0AIAMgAkEBEHgLIAQoApQBIgJFDQAgBSADKQIENwNQIAVB0ABqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAAkAgAigCyAFFDQAgAigCCA0AIAIoAtABRQ0AIAMgAkEBEHgLIAQoApgBIgJFDQAgBSADKQIENwNIIAVByABqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAAkAgAigCyAFFDQAgAigCCA0AIAIoAtABRQ0AIAMgAkEBEHgLIAQoApwBIgJFDQAgBSADKQIENwNAIAVBQGsgAhBiIQEgAygCDCABQQN0aiIBIAEoAgBBAWo2AgACQCACKALIAUUNACACKAIIDQAgAigC0AFFDQAgAyACQQEQeAsgBCgCoAEiAkUNACAFIAMpAgQ3AzggBUE4aiACEGIhASADKAIMIAFBA3RqIgEgASgCAEEBajYCAAJAIAIoAsgBRQ0AIAIoAggNACACKALQAUUNACADIAJBARB4CyAEKAKkASICRQ0AIAUgAykCBDcDMCAFQTBqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAAkAgAigCyAFFDQAgAigCCA0AIAIoAtABRQ0AIAMgAkEBEHgLIAQoAqgBIgJFDQAgBSADKQIENwMoIAVBKGogAhBiIQEgAygCDCABQQN0aiIBIAEoAgBBAWo2AgACQCACKALIAUUNACACKAIIDQAgAigC0AFFDQAgAyACQQEQeAsgBCgCrAEiAkUNACAFIAMpAgQ3AyAgBUEgaiACEGIhASADKAIMIAFBA3RqIgEgASgCAEEBajYCAAJAIAIoAsgBRQ0AIAIoAggNACACKALQAUUNACADIAJBARB4CyAEKAKwASICRQ0AIAUgAykCBDcDGCAFQRhqIAIQYiEBIAMoAgwgAUEDdGoiASABKAIAQQFqNgIAIAIoAsgBRQ0AIAIoAggNACACKALQAUUNACADIAJBARB4CyAAQQFqIgAgCygCBCIISA0ACwsgDSAIIA0bIhVBAEoEQEEAIQgDQCAIIQAgFQJ/AkAgDQRAIBIgAEECdGooAgAiAEF/Rg0BCwJAIAsoAgwgAEECdGooAgAiASgCjAEiAEUNACADIAAQhgEgASgCkAEiAEUNACADIAAQhgEgASgClAEiAEUNACADIAAQhgEgASgCmAEiAEUNACADIAAQhgEgASgCnAEiAEUNACADIAAQhgEgASgCoAEiAEUNACADIAAQhgEgASgCpAEiAEUNACADIAAQhgEgASgCqAEiAEUNACADIAAQhgEgASgCrAEiAEUNACADIAAQhgEgASgCsAEiAEUNACADIAAQhgELIAMgARCGASANRQ0AIBIgCEECdGooAgBBf0YNACAIQQFqDAELIBEgCCANGyIAIAggCEEBaiIUIA0bIhZIBEADQCAAIQIgCygCDCANBH8gEiAAQQJ0aigCAAUgAgtBAnRqKAIAIRdBACEIA0AgFyAIQQJ0aigCjAEiAARAIAUgAykCBDcDECAFQRBqIAAQYiEBIAMoAgwgAUEDdGoiBCAEKAIAQQFrIgE2AgACQCABDQAgBCgCBA0AIAAoAsgBIgEEQCAFIAMpAgQ3AwggBUEIaiABEGIhACADKAIMIABBA3RqIgQgBCgCBEEBayIANgIEIAANASABIQAgBCgCAA0BCyMAQSBrIg8kACADKAIAIgZFBEAgAygCFCEYIA8gAykCBDcDGCAYIA9BGGogABBiQQJ0aigCACEGCwJAAkACQCAGKAIAIgEgACgCCEcNACAAKALQASEQIAEgABDnBCIAIAYoAgwiASAAIAFwayABcGohDgJAIAYoAhAiAUEATARAQQAhAAwBCyAOIBBqIQRBACEAA0AgECAGIABBA3RqIgooAhQiDCAKKAIYIgdqRgRAIAogByAOaiIJNgIYIAAgAUEBayIOTg0DIAYgAEEBaiIEQQN0aiIHKAIUIAkgDGpHDQMgCiAHKAIYIAlqNgIYIAYgDjYCECAEIA5ODQMCQCABIABrQQJrIgxBAkkEQCAEIQAMAQsgBCAMQX5xIglqIQBBACEBA0AgBiABIARqQQN0aiIHIAf9AAIc/QsCFCABQQJqIgEgCUcNAAsgCSAMRg0ECyAGQRRqIQEDQCABIABBA3RqIAEgAEEBaiIAQQN0aikCADcCACAAIA5HDQALDAMLIAQgDEYEQCAKIBA2AhQgCiAHIA5qIgc2AhggAEUNAyAQIABBA3QgBmoiCSgCDCAJKAIQIgRqRw0DIAkgBCAHajYCECAGIAFBAWsiDDYCECAAIAxODQMCQCAMIABrIglBAkkEQCAAIQEMAQsgACAJQX5xIgdqIQFBACEKA0AgBiAAIApqQQN0aiIEIAT9AAIc/QsCFCAKQQJqIgogB0cNAAsgByAJRg0ECyAGQRRqIQADQCAAIAFBA3RqIAAgAUEBaiIBQQN0aikCADcCACABIAxHDQALDAMLIABBAWoiACABRw0ACyABQYACTg0CQQAhAAJAA0AgBiAAQQN0aigCFCAQTw0BIABBAWoiACABRw0ACyABIQAMAQsgACABTg0AIAEgAEF/c2ohGSABIABrQQNxIgQEQEEAIQogBkEUaiEJA0AgCSABQQN0aiAJIAFBAWsiAUEDdGopAgA3AgAgCkEBaiIKIARHDQALCyAZQQJLBEAgBkEUaiEHA0AgByABQQN0aiIEIARBCGspAgA3AgAgBEEQayAEQRhrIgT9AAIA/QsCACAEIAcgAUEEayIBQQN0aikCADcCACAAIAFIDQALCyAGKAIQIQELIAYgAEEDdGoiACAONgIYIAAgEDYCFCAGIAFBAWo2AhALIA9BIGokAAwBC0G8wwIoAgAQMBogD0GG3QA2AgggD0HPATYCBCAPQdonNgIAQbjDAigCAEHL5AAgDxAxEAAACwsgCEEBaiIIQQpHDQELCyACQQFqIgAgFkcNAAsLIBQgESANGyERIBQLIghHDQALCyAFQfAAaiQAIANBADYCACATKAKUEBoLggUCA38BfiMAQeAAayICJAAgASEDAkACQAJAAkACQAJAAkACQAJAIAAoAkAOSQcICAgIBwgIBwcHBwcHBwcHCAgICAgICAgIBwcIBwcHBwcHBwcICAEICAgHBwgICAcHCAgIBwgICAcHBwgABwcHBwcCAwQICAUGC0EBIQMjAEEQayIEJAAgACgCQEE9RwRAQbzDAigCABAwGiAEQb8qNgIIIARB6hc2AgQgBEHkJjYCAEG4wwIoAgBBy+QAIAQQMRAAAAsgACgCRCEAIARBEGokACAAQQdJDQcgASEDIABBB2tBAk0NB0G8wwIoAgAQMBogAkGbITYCSCACQcT8ADYCRCACQeQmNgJAQbjDAigCAEHL5AAgAkFAaxAxEAAAC0EEIAEgAUEEThsiASAAKAKMASIAKQMgIAApAxh+IAApAyh+IgWnIAUgAaxVGyEDDAYLIAEgACgCSCIAIAEgACABSBsgAEF/RhshAwwFCyABIAAoAkgiACABIAAgAUgbIABBf0YbIQMMBAsgASAAKAJIIgAgASAAIAFIGyAAQX9GGyEDDAMLQbzDAigCABAwGiACQZshNgJYIAJB9/0ANgJUIAJB5CY2AlBBuMMCKAIAQcvkACACQdAAahAxEAAACyACQcwQNgIwQbjDAigCACIBQYLiACACQTBqEDECQCAAKAJAIgBBxwBNBEAgAiAAQQJ0QcCgAWooAgA2AhAgAUHw5AAgAkEQahAxDAELIAIgADYCICABQaDuACACQSBqEDELQbzDAigCABAwGiACQZshNgIIIAJBgf4ANgIEIAJB5CY2AgAgAUHL5AAgAhAxEAAAC0EBIQMLIAJB4ABqJAAgAwtJAQJ/IAAoAgQiBUEIdSEGIAAoAgAiACABIAVBAXEEfyAGIAIoAgBqKAIABSAGCyACaiADQQIgBUECcRsgBCAAKAIAKAIYEQsACxkBAX8gACgCACIBBEAgARCKBQsgARAvIAALewEBfyMAQRBrIgMkAAJAIAJBCk0EQCAAIAAtAAtBgAFxIAJyOgALIAAgAC0AC0H/AHE6AAsgACABIAIQdyADQQA6AA8gACACaiADLQAPOgAADAELIABBCiACQQprIAAtAAtB/wBxIgBBACAAIAIgARDMAQsgA0EQaiQAC3gBAn8jAEEQayIEJAACQCACIAAoAghB/////wdxIgNJBEAgACgCACEDIAAgAjYCBCADIAEgAhB3IARBADoADyACIANqIAQtAA86AAAMAQsgACADQQFrIAIgA2tBAWogACgCBCIAQQAgACACIAEQzAELIARBEGokAAsJACAAIAEQmwMLUQEBfyMAQSBrIggkACAIIAM3AwggCCACNwMAIAggBDcDECAAIAFBAyAIIAcQqwIiACAEpyAGbDYCPCAAIAY2AjggACAFNgI0IAhBIGokACAAC4sDAgd/A34jAEHQAGsiBSQAAkACQCABKAIwIgYgASgCACIIQSRsIgdBmJsBaigCAEcNACABNQI0IgwgASkDECIOIAatfiAHQZSbAWo0AgB/Ug0AIAE1AjgiDSAMIAEpAxgiDH5SDQAgATUCPCANIAEpAyAiDX5SDQAgASkDKCAMIA5+IA1+fiACIAN+IAR+Ug0BIAEoAogBIQsgBSAENwNAIAUgAzcDOCAFIAI3AzBBACEHIAAgCEEDIAVBMGogAUEAEEkhCiAFIAFB1AFqNgIAIApBktUAIAUQcyIGQR42AkAgCwRAIAAgBigCACAGKAIMIAZBEGpBAEEAEEkhBwsgBiABNgKMASAGIAc2AogBIAVB0ABqJAAgBg8LQbzDAigCABAwGiAFQcXXADYCKCAFQZcjNgIkIAVB5CY2AiBBuMMCKAIAQcvkACAFQSBqEDEQAAALQbzDAigCABAwGiAFQYs7NgIYIAVBmCM2AhQgBUHkJjYCEEG4wwIoAgBBy+QAIAVBEGoQMRAAAAsEAEEEC/8CAgd/A34jAEFAaiIEJAACQAJAIAEoAjAiBSABKAIAIgdBJGwiBkGYmwFqKAIARw0AIAE1AjQiCyABKQMQIg0gBa1+IAZBlJsBajQCAH9SDQAgATUCOCIMIAsgASkDGCILflINACABNQI8IAwgASkDICIMflINACABKQMoIAsgDX4gDH5+IAIgA35SDQEgASgCiAEhCiAEIAM3AzggBCACNwMwQQAhBiAAIAdBAiAEQTBqIAFBABBJIQkgBCABQdQBajYCACAJQZLVACAEEHMiBUEeNgJAIAoEQCAAIAUoAgAgBSgCDCAFQRBqQQBBABBJIQYLIAUgATYCjAEgBSAGNgKIASAEQUBrJAAgBQ8LQbzDAigCABAwGiAEQcXXADYCKCAEQf0iNgIkIARB5CY2AiBBuMMCKAIAQcvkACAEQSBqEDEQAAALQbzDAigCABAwGiAEQaU9NgIYIARB/iI2AhQgBEHkJjYCEEG4wwIoAgBBy+QAIARBEGoQMRAAAAukAQEBfwJAQYyKNf4SAABBAXENAEGMijUQVEUNAAJAQYCKNf4SAABBAXENAEGAijUQVEUNABDUBUH4iTVB6JY1NgIAQfyJNUH4iTU2AgBBgIo1EFMLQYSKNUH8iTUoAgAoAgAiATYCACABQQRqQQH+HgIAGkGIijVBhIo1NgIAQYyKNRBTCyAAQYiKNSgCACgCACIBNgIAIAFBBGpBAf4eAgAaIAALXwEEfyABKAKIASEFIAAgASgCACABKAIMIAFBEGpBAEEAEEkiAkK9gICA8AA3A0AgBQRAIAAgAigCACACKAIMIAJBEGpBAEEAEEkhAwsgAiABNgKMASACIAM2AogBIAILRwEBfyMAQRBrIgIkAAJAIAEtAAtBB3ZFBEAgACABKAIINgIIIAAgASkCADcCAAwBCyAAIAEoAgAgASgCBBBrCyACQRBqJAALCABB/////wcLBQBB/wALdgEBfyMAQRBrIgIkACACIAA2AgwCQCAAIAFGDQADQCACIAFBBGsiATYCCCAAIAFPDQEgAigCDCIAKAIAIQEgACACKAIIIgAoAgA2AgAgACABNgIAIAIgAigCDEEEaiIANgIMIAIoAgghAQwACwALIAJBEGokAAv2BAEIfyMAQRBrIgskACAGEGwhCSALQQRqIgcgBhC/ASIIIAgoAgAoAhQRAgACQAJ/IActAAtBB3YEQCAHKAIEDAELIActAAtB/wBxC0UEQCAJIAAgAiADIAkoAgAoAjARCAAaIAUgAyACIABrQQJ0aiIGNgIADAELIAUgAzYCAAJAAkAgACIKLQAAIgZBK2sOAwABAAELIAkgBsAgCSgCACgCLBEEACEHIAUgBSgCACIGQQRqNgIAIAYgBzYCACAAQQFqIQoLAkAgAiAKa0ECSA0AIAotAABBMEcNACAKLQABQSByQfgARw0AIAlBMCAJKAIAKAIsEQQAIQcgBSAFKAIAIgZBBGo2AgAgBiAHNgIAIAkgCiwAASAJKAIAKAIsEQQAIQcgBSAFKAIAIgZBBGo2AgAgBiAHNgIAIApBAmohCgsgCiACEKwBIAggCCgCACgCEBEAACEOQQAhByAKIQYDfyACIAZNBH8gAyAKIABrQQJ0aiAFKAIAEOoBIAUoAgAFAkACfyALQQRqIggtAAtBB3YEQCAIKAIADAELIAgLIAdqLQAARQ0AIAwCfyAILQALQQd2BEAgCCgCAAwBCyAICyAHaiwAAEcNACAFIAUoAgAiDUEEajYCACANIA42AgAgByAHAn8gCC0AC0EHdgRAIAgoAgQMAQsgCC0AC0H/AHELQQFrSWohB0EAIQwLIAkgBiwAACAJKAIAKAIsEQQAIQ0gBSAFKAIAIghBBGo2AgAgCCANNgIAIAZBAWohBiAMQQFqIQwMAQsLIQYLIAQgBiADIAEgAGtBAnRqIAEgAkYbNgIAIAtBBGoQMxogC0EQaiQAC9ABAQJ/IAJBgBBxBEAgAEErOgAAIABBAWohAAsgAkGACHEEQCAAQSM6AAAgAEEBaiEACyACQYQCcSIDQYQCRwRAIABBrtQAOwAAIABBAmohAAsgAkGAgAFxIQIDQCABLQAAIgQEQCAAIAQ6AAAgAEEBaiEAIAFBAWohAQwBCwsgAAJ/AkAgA0GAAkcEQCADQQRHDQFBxgBB5gAgAhsMAgtBxQBB5QAgAhsMAQtBwQBB4QAgAhsgA0GEAkYNABpBxwBB5wAgAhsLOgAAIANBhAJHC+0EAQh/IwBBEGsiCyQAIAYQciEJIAtBBGoiByAGEMEBIgggCCgCACgCFBECAAJAAn8gBy0AC0EHdgRAIAcoAgQMAQsgBy0AC0H/AHELRQRAIAkgACACIAMgCSgCACgCIBEIABogBSADIAIgAGtqIgY2AgAMAQsgBSADNgIAAkACQCAAIgotAAAiBkEraw4DAAEAAQsgCSAGwCAJKAIAKAIcEQQAIQcgBSAFKAIAIgZBAWo2AgAgBiAHOgAAIABBAWohCgsCQCACIAprQQJIDQAgCi0AAEEwRw0AIAotAAFBIHJB+ABHDQAgCUEwIAkoAgAoAhwRBAAhByAFIAUoAgAiBkEBajYCACAGIAc6AAAgCSAKLAABIAkoAgAoAhwRBAAhByAFIAUoAgAiBkEBajYCACAGIAc6AAAgCkECaiEKCyAKIAIQrAEgCCAIKAIAKAIQEQAAIQ5BACEHIAohBgN/IAIgBk0EfyADIAogAGtqIAUoAgAQrAEgBSgCAAUCQAJ/IAtBBGoiCC0AC0EHdgRAIAgoAgAMAQsgCAsgB2otAABFDQAgDAJ/IAgtAAtBB3YEQCAIKAIADAELIAgLIAdqLAAARw0AIAUgBSgCACINQQFqNgIAIA0gDjoAACAHIAcCfyAILQALQQd2BEAgCCgCBAwBCyAILQALQf8AcQtBAWtJaiEHQQAhDAsgCSAGLAAAIAkoAgAoAhwRBAAhDSAFIAUoAgAiCEEBajYCACAIIA06AAAgBkEBaiEGIAxBAWohDAwBCwshBgsgBCAGIAMgASAAa2ogASACRhs2AgAgC0EEahAzGiALQRBqJAAL7QUBC38jAEGAAWsiCSQAIAkgATYCfCAJQfYBNgIQIAlBCGpBACAJQRBqIggQUSELAkACQCADIAJrQQxtIgpB5QBPBEAgChA7IghFDQEgCygCACEBIAsgCDYCACABBEAgASALKAIEEQEACwsgCCEHIAIhAQNAIAEgA0YEQANAIAAgCUH8AGoQQkEBIAobBEAgACAJQfwAahBCBEAgBSAFKAIAQQJyNgIACwwFCwJ/IAAoAgAiBygCDCIBIAcoAhBGBEAgByAHKAIAKAIkEQAADAELIAEoAgALIQ4gBkUEQCAEIA4gBCgCACgCHBEEACEOCyAPQQFqIQ1BACEQIAghByACIQEDQCABIANGBEAgDSEPIBBFDQIgABBcGiAIIQcgAiEBIAogDGpBAkkNAgNAIAEgA0YEQAwEBQJAIActAABBAkcNAAJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyAPRg0AIAdBADoAACAMQQFrIQwLIAdBAWohByABQQxqIQEMAQsACwAFAkAgBy0AAEEBRw0AAn8gAS0AC0EHdgRAIAEoAgAMAQsgAQsgD0ECdGooAgAhEQJAIAYEfyARBSAEIBEgBCgCACgCHBEEAAsgDkYEQEEBIRACfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQsgDUcNAiAHQQI6AAAgDEEBaiEMDAELIAdBADoAAAsgCkEBayEKCyAHQQFqIQcgAUEMaiEBDAELAAsACwAFIAdBAkEBAn8gAS0AC0EHdgRAIAEoAgQMAQsgAS0AC0H/AHELRSINGzoAACAHQQFqIQcgAUEMaiEBIAwgDWohDCAKIA1rIQoMAQsACwALEEYACwJAAkADQCACIANGDQEgCC0AAEECRwRAIAhBAWohCCACQQxqIQIMAQsLIAIhAwwBCyAFIAUoAgBBBHI2AgALIAsoAgAhACALQQA2AgAgAARAIAAgCygCBBEBAAsgCUGAAWokACADC/QFAQt/IwBBgAFrIgkkACAJIAE2AnwgCUH2ATYCECAJQQhqQQAgCUEQaiIIEFEhCwJAAkAgAyACa0EMbSIKQeUATwRAIAoQOyIIRQ0BIAsoAgAhASALIAg2AgAgAQRAIAEgCygCBBEBAAsLIAghByACIQEDQCABIANGBEADQCAAIAlB/ABqEENBASAKGwRAIAAgCUH8AGoQQwRAIAUgBSgCAEECcjYCAAsMBQsCfyAAKAIAIgcoAgwiASAHKAIQRgRAIAcgBygCACgCJBEAAAwBCyABLQAAC8AhDiAGRQRAIAQgDiAEKAIAKAIMEQQAIQ4LIA9BAWohDUEAIRAgCCEHIAIhAQNAIAEgA0YEQCANIQ8gEEUNAiAAEF0aIAghByACIQEgCiAMakECSQ0CA0AgASADRgRADAQFAkAgBy0AAEECRw0AAn8gAS0AC0EHdgRAIAEoAgQMAQsgAS0AC0H/AHELIA9GDQAgB0EAOgAAIAxBAWshDAsgB0EBaiEHIAFBDGohAQwBCwALAAUCQCAHLQAAQQFHDQACfyABLQALQQd2BEAgASgCAAwBCyABCyAPai0AACERAkAgDkH/AXEgBgR/IBEFIAQgEcAgBCgCACgCDBEEAAtB/wFxRgRAQQEhEAJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyANRw0CIAdBAjoAACAMQQFqIQwMAQsgB0EAOgAACyAKQQFrIQoLIAdBAWohByABQQxqIQEMAQsACwALAAUgB0ECQQECfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQtFIg0bOgAAIAdBAWohByABQQxqIQEgDCANaiEMIAogDWshCgwBCwALAAsQRgALAkACQANAIAIgA0YNASAILQAAQQJHBEAgCEEBaiEIIAJBDGohAgwBCwsgAiEDDAELIAUgBSgCAEEEcjYCAAsgCygCACEAIAtBADYCACAABEAgACALKAIEEQEACyAJQYABaiQAIAMLvgIBBH8gA0GIiDUgAxsiBSgCACEDAkACfwJAIAFFBEAgAw0BQQAPC0F+IAJFDQEaAkAgAwRAIAIhBAwBCyABLQAAIgPAIgRBAE4EQCAABEAgACADNgIACyAEQQBHDwsjAygCYCgCAEUEQEEBIABFDQMaIAAgBEH/vwNxNgIAQQEPCyADQcIBayIDQTJLDQEgA0ECdEGwzwJqKAIAIQMgAkEBayIERQ0DIAFBAWohAQsgAS0AACIGQQN2IgdBEGsgA0EadSAHanJBB0sNAANAIARBAWshBCAGQYABayADQQZ0ciIDQQBOBEAgBUEANgIAIAAEQCAAIAM2AgALIAIgBGsPCyAERQ0DIAFBAWoiAS0AACIGQcABcUGAAUYNAAsLIAVBADYCACMDQRxqQRk2AgBBfwsPCyAFIAM2AgBBfgsJACABQQEQ9AMLcQEBfyAAQdTIAjYCACAAEPcDGgJAIAAtAGBFDQAgACgCICIBRQ0AIAEQLwsCQCAALQBhRQ0AIAAoAjgiAUUNACABEC8LIABB5McCNgIAIAAoAgQiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAALDwAgACAAKAIQIAFyELsCC7YLAQZ/IAAgAWohBQJAAkAgACgCBCICQQFxDQAgAkEDcUUNASAAKAIAIgIgAWohAQJAAkACQCAAIAJrIgBBlIQ1KAIARwRAIAJB/wFNBEAgAkEDdiEEIAAoAggiAyAAKAIMIgJHDQJBgIQ1QYCENSgCAEF+IAR3cTYCAAwFCyAAKAIYIQYgACAAKAIMIgJHBEBBkIQ1KAIAGiAAKAIIIgMgAjYCDCACIAM2AggMBAsgAEEUaiIEKAIAIgNFBEAgACgCECIDRQ0DIABBEGohBAsDQCAEIQcgAyICQRRqIgQoAgAiAw0AIAJBEGohBCACKAIQIgMNAAsgB0EANgIADAMLIAUoAgQiAkEDcUEDRw0DQYiENSABNgIAIAUgAkF+cTYCBCAAIAFBAXI2AgQgBSABNgIADwsgAyACNgIMIAIgAzYCCAwCC0EAIQILIAZFDQACQCAAKAIcIgNBAnRBsIY1aiIEKAIAIABGBEAgBCACNgIAIAINAUGEhDVBhIQ1KAIAQX4gA3dxNgIADAILIAZBEEEUIAYoAhAgAEYbaiACNgIAIAJFDQELIAIgBjYCGCAAKAIQIgMEQCACIAM2AhAgAyACNgIYCyAAKAIUIgNFDQAgAiADNgIUIAMgAjYCGAsCQAJAAkACQCAFKAIEIgJBAnFFBEBBmIQ1KAIAIAVGBEBBmIQ1IAA2AgBBjIQ1QYyENSgCACABaiIBNgIAIAAgAUEBcjYCBCAAQZSENSgCAEcNBkGIhDVBADYCAEGUhDVBADYCAA8LQZSENSgCACAFRgRAQZSENSAANgIAQYiENUGIhDUoAgAgAWoiATYCACAAIAFBAXI2AgQgACABaiABNgIADwsgAkF4cSABaiEBIAJB/wFNBEAgAkEDdiEEIAUoAgwiAiAFKAIIIgNGBEBBgIQ1QYCENSgCAEF+IAR3cTYCAAwFCyADIAI2AgwgAiADNgIIDAQLIAUoAhghBiAFIAUoAgwiAkcEQEGQhDUoAgAaIAUoAggiAyACNgIMIAIgAzYCCAwDCyAFQRRqIgQoAgAiA0UEQCAFKAIQIgNFDQIgBUEQaiEECwNAIAQhByADIgJBFGoiBCgCACIDDQAgAkEQaiEEIAIoAhAiAw0ACyAHQQA2AgAMAgsgBSACQX5xNgIEIAAgAUEBcjYCBCAAIAFqIAE2AgAMAwtBACECCyAGRQ0AAkAgBSgCHCIDQQJ0QbCGNWoiBCgCACAFRgRAIAQgAjYCACACDQFBhIQ1QYSENSgCAEF+IAN3cTYCAAwCCyAGQRBBFCAGKAIQIAVGG2ogAjYCACACRQ0BCyACIAY2AhggBSgCECIDBEAgAiADNgIQIAMgAjYCGAsgBSgCFCIDRQ0AIAIgAzYCFCADIAI2AhgLIAAgAUEBcjYCBCAAIAFqIAE2AgAgAEGUhDUoAgBHDQBBiIQ1IAE2AgAPCyABQf8BTQRAIAFBeHFBqIQ1aiECAn9BgIQ1KAIAIgNBASABQQN2dCIBcUUEQEGAhDUgASADcjYCACACDAELIAIoAggLIQEgAiAANgIIIAEgADYCDCAAIAI2AgwgACABNgIIDwtBHyEDIAFB////B00EQCABQSYgAUEIdmciAmt2QQFxIAJBAXRrQT5qIQMLIAAgAzYCHCAAQgA3AhAgA0ECdEGwhjVqIQICQAJAQYSENSgCACIEQQEgA3QiB3FFBEBBhIQ1IAQgB3I2AgAgAiAANgIAIAAgAjYCGAwBCyABQRkgA0EBdmtBACADQR9HG3QhAyACKAIAIQIDQCACIgQoAgRBeHEgAUYNAiADQR12IQIgA0EBdCEDIAQgAkEEcWoiB0EQaigCACICDQALIAcgADYCECAAIAQ2AhgLIAAgADYCDCAAIAA2AggPCyAEKAIIIgEgADYCDCAEIAA2AgggAEEANgIYIAAgBDYCDCAAIAE2AggLC5ADAQZ/IAAtAABBD3FFBEAgAEEEakEAQQr+SAIAQQpxDwsCfyAAKAIAIQICQAJAAkAjAyIBKAIYIgQgACgCBCIDQf////8DcSIGRw0AAkAgAkEIcUUNACAAKAIUQQBODQAgAEEANgIUIANBgICAgARxIQMMAgsgAkEDcUEBRw0AQQYhBSAAKAIUIgFB/v///wdLDQIgACABQQFqNgIUQQAMAwtBOCEFIAZB/////wNGDQECQCAGDQBBACADIAJBBHEbDQAgAyAAQQRqIAMgAkGAAXEEfyABKAJQRQRAIAFBdDYCUAsgACgCCCEGIAEgAEEQajYCVCAEQYCAgIB4ciAEIAYbBSAECyADQYCAgIAEcXL+SAIARg0BIAFBADYCVCACQQxxQQxHDQAgACgCCA0CC0EKDAILIAEoAkwhAiAAIAFBzABqIgU2AgwgACACNgIQIABBEGohBCACIAVHBEAgAkEEayAENgIACyABIAQ2AkxBACEFIAFBADYCVCADRQ0AIABBADYCFEE+DAELIAULC5sFAQV/IwBBMGsiBSQAAkAgAEUEQEEcIQQMAQtBmPM0KAIARQRAQZjzNEErNgIAC0GZ8TQtAABFBEAQ/AEoAgAiAwRAA0ACQCADRQ0AIAMoAkxBAE4NACADQQA2AkwLIAMoAjgiAw0ACwtB1PI0ENMBAkBBlPE0KAIAIgNFDQAgAygCTEEATg0AIANBADYCTAsCQEHAuwMoAgAiA0UNACADKAJMQQBODQAgA0EANgJMCwJAQai6AygCACIDRQ0AIAMoAkxBAE4NACADQQA2AkwLQZnxNEEBOgAACyAFQQhqQQBBKPwLACAFQYy5AygCACIDNgIEQZC5AygCAEGaAWoiBEEAIANBD2ogBSgCDBtqIgYQOyIDQQAgBBCgASADIAY2AjAgAyADNgIsIAMgAzYCAEGY8zRBmPM0KAIAIgRBAWo2AgAgAyADQcwAajYCTCADIAQ2AhggA0G48TQ2AmAgA0EDQQIgBSgCEBs2AiAgAyAFKAIEIgY2AjggAyADQYcBakF8cSIENgJ0IARBEGohBEGQuQMoAgAEQCADIARBA2pBfHEiBDYCSEGQuQMoAgAgBGohBAsgAyAFKAIMIgcgBCAGakEPakFwcSAHGzYCNCADEIwEIwMhBBDKAiAEKAIMIQYgAyAENgIIIAMgBjYCDCAGIAM2AgggAygCCCADNgIMEMkCQZzxNEGc8TQoAgAiBEEBajYCACAERQRAQZvxNEEBOgAACyADIAVBBGogASACEB8iBARAQZzxNEGc8TQoAgBBAWsiADYCACAARQRAQZvxNEEAOgAACxDKAiADKAIMIgAgAygCCDYCCCADKAIIIAA2AgwgAyADNgIMIAMgAzYCCBDJAgwBCyAAIAM2AgALIAVBMGokACAECxUAIABBAP5BAgBBAkYEQCAAEI4BCwsyACAAQQBBAf5IAgAEQCAAQQFBAv5IAgAaA0AgAEEAQQIQoQEgAEEAQQL+SAIADQALCwvnAQICfwN8IwBBEGsiAiQAAkACfwJAAkAjBSIDDQAjAyIELQAoQQFHDQAgBC0AKUUNAQtBAUHkACADG7chBRADRAAAAAAAAPB/oCEHIwMhAwNAAkAgAygCJEUEQCAHEAOhIgZEAAAAAAAAAABlRQ0BQckADAQLQQshAAwECyAAIAEgBSAGIAUgBmMbENUBIgRBt39GDQALQQAgBGsMAQtBACAAIAFEAAAAAAAA8H8Q1QFrCyIAQQAgAEFvcUELRhsgACAAQckARxsiAEEbRw0AQRtBAEGI8zQoAgAbIQALIAJBEGokACAACw0AIABB/////wcQtQELrgQBBX8jAEEQayIEJAAgABBWGgJ/AkAgACABEJwEIgNFBEAgACgCHCIDIAAoAiBGBEAgACgCGCADQQF0QQEgAxsiA0ECdBDEASIFRQ0CIAAgAzYCICAAIAU2AhgLIAEQoQQiA0UNASAAIAAoAhwiAUEBajYCHCAAKAIYIAFBAnRqIAM2AgALIAMMAQtBAAshASAAEFIaIAEEfyAEIAIoAgg2AgggBCACKQIANwMAIwBBMGsiAiQAAkACfyABIgAoAhwiA/4QAnwhAQNAQQAgAUUNARogASADIAEgAUEBav5IAnwiAUcNAAtBAQtFBEBBACEDDAELIABBBGoiARBWGiACIAQoAgg2AiAgAiAEKQIANwMYIAAgAkEYahCdBCEDIAEQUhoCfyADBH8gAEEC/kECACEFQQEhAyAAKAIcIgEgBUECRg0BGiACIAA2AiwgAiAANgIQIAJBvgE2AiggAkG/ATYCJCACIAIpAiQ3AwgjAEEQayIDJAAgASgCeEEEahBWGiABKAJ4IQYgAyACKAIQNgIIIAMgAikCCDcDACAGIAMQnQQaIAEoAnhBBGoQUhoCQCABKAJ4QQL+QQIAQQJGDQAgAf4QAoABBEAgAUF//gACABoMAQsgASMDQdDxNBAeCyADQRBqJABBAQVBAAshAyAAKAIcCyIAQQH+JQJ8QQFGBEAgAEH8AGpB/////wcQtQELCyACQTBqJAAgAwVBAAshByAEQRBqJAAgBwsNAEHU8jQQpQRB2PI0C+4BAwJ8An8BfgJ9AkAgALwiA0EUdkH/D3EiBEGwCEkNAEMAAAAAIANBgICAfEYNARogBEH4D08EQCAAIACSDwsgAEMAAAAAXgRAIwBBEGsiA0MAAABwOAIMIAMqAgxDAAAAcJQPCyAAQwAAFsNfRQ0AIwBBEGsiA0MAAAAQOAIMIAMqAgxDAAAAEJQPC0HY2gErAwAgALsiASABQdDaASsDACIBoCICIAGhoSIBokHg2gErAwCgIAEgAaKiQejaASsDACABokQAAAAAAADwP6CgIAK9IgVCL4YgBadBH3FBA3RB0NgBaikDAHy/orYLCxQAQQwQXkEFEHBB0KkDQdIAEAIACxQAQQwQXkEEEHBB0KkDQdIAEAIACxQAQQwQXkEDEHBB0KkDQdIAEAIAC6UEAQR/AkACQAJAIAAoAgQgACgCACICa0E0bSIFQQFqIgNBxZ2xJ0kEQEHEnbEnIAAoAgggAmtBNG0iAkEBdCIEIAMgAyAESRsgAkHiztgTTxsiAwR/IANBxZ2xJ08NAiADQTRsEDIFQQALIgQgBUE0bGoiAiAB/QACAP0LAgAgAiAB/QACEP0LAhAgAiABKAIgNgIgIAIgASgCJDYCJCABQgA3AiAgAf0MAAAAAAAAAAAAAAAAAAAAAP0LAhAgAiABLQAwOgAwIAIgASkCKDcCKCAEIANBNGxqIQMgAkE0aiEFIAAoAgQiASAAKAIAIgRGDQIDQCACQTRrIgIgAUE0ayIB/QACAP0LAgAgAkEANgIYIAIgASgCEDYCECACIAEoAhQ2AhQgAiABKAIYNgIYIAFBADYCGCABQgA3AhAgAkEANgIkIAIgASgCHDYCHCACIAEoAiA2AiAgAiABKAIkNgIkIAFBADYCJCABQgA3AhwgAiABLQAwOgAwIAIgASkCKDcCKCABIARHDQALIAAgAzYCCCAAKAIEIQMgACAFNgIEIAAoAgAhASAAIAI2AgAgASADRg0DA0AgA0E0ayIAKAIcIgIEQCADQRRrIAI2AgAgAhAvCyADQSRrKAIAIgIEQCADQSBrIAI2AgAgAhAvCyAAIgMgAUcNAAsMAwsQNgALEEcACyAAIAM2AgggACAFNgIEIAAgAjYCAAsgAQRAIAEQLwsLqQUBCH8gASAAKAIIIgMgACgCACIEa0EMbU0EQAJAIAAoAgQiBSAEa0EMbSIIIAEgASAISxsiB0UNACAEIQMgByEGIAdBA3EiCQRAA0AgAyACKAIANgIAIAMgAigCBDYCBCADIAItAAg6AAggBkEBayEGIANBDGohAyAKQQFqIgogCUcNAAsLIAdBBEkNAANAIAMgAigCADYCACADIAIoAgQ2AgQgAyACLQAIOgAIIAMgAigCADYCDCADIAIoAgQ2AhAgAyACLQAIOgAUIAMgAigCADYCGCADIAIoAgQ2AhwgAyACLQAIOgAgIAMgAigCADYCJCADIAIoAgQ2AiggAyACLQAIOgAsIANBMGohAyAGQQRrIgYNAAsLIAEgCEsEQCAFIAEgCGtBDGxqIQEDQCAFIAIpAgA3AgAgBSACKAIINgIIIAVBDGoiBSABRw0ACyAAIAE2AgQPCyAAIAQgAUEMbGo2AgQPCyAEBEAgACAENgIEIAQQLyAAQQA2AgggAEIANwIAQQAhAwsCQCABQdaq1aoBTw0AQdWq1aoBIANBDG0iA0EBdCIEIAEgASAESRsgA0Gq1arVAE8bIgNB1qrVqgFPDQAgACADQQxsIgMQMiIENgIEIAAgBDYCACAAIAMgBGo2AgggBCEDIAFBDGwiAUEMayIGQQxuQQFqQQNxIgcEQANAIAMgAikCADcCACADIAIoAgg2AgggA0EMaiEDIAVBAWoiBSAHRw0ACwsgASAEaiEBIAZBJE8EQANAIAMgAikCADcCACADIAIoAgg2AgggAyACKAIINgIUIAMgAikCADcCDCADIAIoAgg2AiAgAyACKQIANwIYIAMgAikCADcCJCADIAIoAgg2AiwgA0EwaiIDIAFHDQALCyAAIAE2AgQPCxA2AAsUAEEMEF5BBhBwQdCpA0HSABACAAsCAAv9BwEHfyAAKAIQIQcgACgCJCEIAkAgAiABIgNGDQACQAJAIAMsAAAiBEEkaw5ZAgEBAQIAAgIBAQIBAQEBAQEBAQEBAQEBAQEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgIBCyAAKAIYDQELIAAgBBBZIANBAWohAwsCQAJAAkACQAJAIAEgA0cNAAJ/AkAgAiABIgNGDQAgA0EBaiIFIAJGDQAgAy0AAEHcAEcNAAJAAkAgBSwAACIEQSRrDloAAQEBAAAAAAEBAAEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAABAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABCyAAIAQQWSADQQJqDAILIAAoAgxB8AdxQcAARgRAIAAgBSACQQAQ1wIMAgsgA0ECQQACf0EAIQUCQAJAIARBeHFBMEcgBEH+AXFBOEdxDQAgBEH/AXEiBEExa0EISw0AIARBMGsiBCAAKAIQSw0BIAAgBBDaAkEBIQULIAUMAQsQ/wEACxtqIQMLIAMLIgMgAUcNAAJAIAEgAkYNACABLQAAQS5HDQBBCBAyIQMgACgCJCIEKAIEIQUgA0GktQE2AgAgAyAFNgIEIAQgAzYCBAwCCyAAIAEgAhDiAiEDCwJAAkAgASADRw0AIAIgA0YNAAJAAkAgASwAACIDQSRrDgUDBgYGAQALIANB3gBHDQVBDBAyIQMgACgCDCEEIAAoAiQiBSgCBCEGIANB9KkBNgIAIAMgBjYCBCADIARB8A9xQYAMRjoACCAFIAM2AgQMAwsCQCAALQAMQQJxBEAgACgCECEEDAELQQwQMiEDIAAgACgCEEEBaiIENgIQIAAoAiQiBSgCBCEGIAMgBDYCCCADQcCxATYCACADIAY2AgQgBSADNgIEIAAgACgCJCgCBDYCJAsgACAAKAIYQQFqNgIYIAAgAUEBaiACEIYCIgUgAkYNBSAFLQAAQSlHDQUgAC0ADEECcUUEQEEMEDIhAyAAKAIkIgYoAgQhCSADIAQ2AgggA0GQsgE2AgAgAyAJNgIEIAYgAzYCBCAAIAAoAiQoAgQ2AiQLIAAgACgCGEEBazYCGCAFQQFqIQMLIAEgA0cNAgwDC0EMEDIhAyAAKAIMIQQgACgCJCIFKAIEIQYgA0G8qgE2AgAgAyAGNgIEIAMgBEHwD3FBgAxGOgAIIAUgAzYCBAsgACAAKAIkKAIENgIkIAFBAWohAwsgACADIAIgCCAHQQFqIAAoAhBBAWoQ4wIhAQsgAQ8LEIMCAAuxAgEEfyAAKAIkIQYCQCAAIAEgAhCFAiIDIAFGDQADQCAAIAMiBCACEIUCIgMgBEcNAAsgASAERg0AIAIgBEcEQANAIAQtAABB/ABHBEAgBA8LIAAoAiQhBSAAIARBAWoiASACEIUCIgMgAUYNAgNAIAAgAyIEIAIQhQIiAyAERw0ACyABIARGDQJBDBAyIQMgBigCBCEBIAMgBSgCBDYCCCADIAE2AgQgA0GctAE2AgAgBiADNgIEIAVBADYCBEEIEDIhAyAAKAIkKAIEIQEgA0HIqAE2AgAgAyABNgIEIAUgAzYCBCAAKAIkQQA2AgRBCBAyIQMgBSgCBCEBIANB3LQBNgIAIAMgATYCBCAAKAIkIAM2AgQgACAFKAIENgIkIAIgBEcNAAsLIAIPCxDGBAALrgIBBH8gACgCACIDBEAgAyECIAMgACgCBCIERwRAA0AgBEEMayICKAIAIgUEQCAEQQhrIAU2AgAgBRAvCyACIgQgA0cNAAsgACgCACECCyAAIAM2AgQgAhAvIABBADYCCCAAQgA3AgALIAAgASgCADYCACAAIAEoAgQ2AgQgACABKAIINgIIIAFBADYCCCABQgA3AgAgACgCDCIDBEAgAyECIAMgACgCECIERwRAA0AgBEEMayICKAIAIgUEQCAEQQhrIAU2AgAgBRAvCyACIgQgA0cNAAsgACgCDCECCyAAIAM2AhAgAhAvIABBADYCFCAAQgA3AgwLIAAgASgCDDYCDCAAIAEoAhA2AhAgACABKAIUNgIUIAFBADYCFCABQgA3AgwgACABKQIYNwIYC/ABAgR/AX4jAEFAaiICJAAgAiABQsD8FX8iBj4CACACIAZCgKOkfn4gAUIKfnwiAULg1AN/IgY+AgQgAiAGQqCrfH4gAXwiAULoB38iBj4CCCACIAZCmPj//w9+IAF8PgIQIAJB0coANgIMIAJBIGoiBEEgQdslIAIQxQIaIAQQaCIDQfD///8HSQRAAkAgA0EKTQRAIAAgAzoACwwBCyADQQ9yQQFqIgUQMiEEIAAgBUGAgICAeHI2AgggACAENgIAIAAgAzYCBCAEIQALIAAgAkEgaiAD/AoAACAAIANqQQA6AAAgAkFAayQADwsQTQAL60EEGX8FfQN8AX4jAEGAAWsiBiQAAkACQCAAKAIAQQH+HgIAIhQgACgCBCgCAEgEQCAGQdwAaiERIAZB0ABqIRIDQAJAIAAoAggoAgAgFEHYFGxqIggtALECDQAgCC0AsAINAAJAAkACQAJAAkACQCAAKAIMIgEoAgAOAgABBgsgACgCFCgCACILKAL8ASECIAsoAsABIQogACgCECoCAEO9N4Y1XUUNAUQAAAAAAAAAACEfQQAhBEEAIQNEAAAAAAAAAAAhICACIApODQMgCiACayIBQQFxIQsgCCgCtAIhByACQQFqIApGBEAgAiEBDAMLIAFBfnEhDCACIQFBACEFA0ACfwJAIAcgAUECdGoqAgAiGkMAAID/Ww0AICAgGrsiIaAhICAfICFjRQ0AIAEMAQsgHyEhIAMLIQkCQCAHIAFBAWoiA0ECdGoqAgAiGkMAAID/XARAICAgGrsiH6AhICAfICFkDQELIAkhAyAhIR8LIAFBAmohASAMIAVBAmoiBUcNAAsMAgsgASgCdCENAkAgACgCFCgCACITKALAASIMIAgoAtwCIgIgCCgC2AIiBGtBBHUiAUsEQEEAIQpBACEHAkAgDCABayIBIAgoAuACIgUgAmtBBHVNBEACQCABRQ0AIAIhAyABQQdxIgQEQEEAIQUDQCADQQA2AgggA0IANwMAIANBEGohAyAFQQFqIgUgBEcNAAsLIAFBBHQgAmohAiABQQFrQf////8AcUEHSQ0AA0AgA0IANwNwIANCADcDYCADQgA3A1AgA0IANwNAIANCADcDMCADQgA3AyAgA0IANwMQIANBADYCCCADQgA3AwAgA0EANgJ4IANBADYCaCADQQA2AlggA0EANgJIIANBADYCOCADQQA2AiggA0EANgIYIANBgAFqIgMgAkcNAAsLIAggAjYC3AIMAQsCQCACIAgoAtgCIgRrQQR1IgsgAWoiA0GAgICAAUkEQEH/////ACAFIARrIgVBA3UiCSADIAMgCUkbIAVB8P///wdPGyIJBEAgCUGAgICAAU8NAiAJQQR0EDIhBwsgByALQQR0aiIFIQMgAUEHcSILBEADQCADQQA2AgggA0IANwMAIANBEGohAyAKQQFqIgogC0cNAAsLIAFBBHQgBWohCiABQQFrQf////8AcUEHTwRAA0AgA0IANwNwIANCADcDYCADQgA3A1AgA0IANwNAIANCADcDMCADQgA3AyAgA0IANwMQIANBADYCCCADQgA3AwAgA0EANgJ4IANBADYCaCADQQA2AlggA0EANgJIIANBADYCOCADQQA2AiggA0EANgIYIANBgAFqIgMgCkcNAAsLIAIgBEcEQANAIAVBEGsiBSACQRBrIgIpAwA3AwAgBSACKAIINgIIIAIgBEcNAAsLIAggByAJQQR0ajYC4AIgCCAKNgLcAiAIKALYAiEBIAggBTYC2AIgAQRAIAEQLwsMAgsMDAsQRwALIAgoAtgCIQQMAQsgASAMTQ0AIAggBCAMQQR0ajYC3AILAkAgDEEATA0AIAgoAsACIQJBACEBIAxBAUcEQCAMQX5xIQVBACELA0AgAiABQQJ0aioCACEaIAQgAUEEdGoiAyABNgIIIAMgGrs5AwAgAiABQQFyIgNBAnRqKgIAIRogBCADQQR0aiIJIAM2AgggCSAauzkDACABQQJqIQEgC0ECaiILIAVHDQALCyAMQQFxRQ0AIAIgAUECdGoqAgAhGiAEIAFBBHRqIgIgATYCCCACIBq7OQMACyAGAn8gDUUEQEEAIQlBAAwBCyAEIA1B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QQJ0IgIgACgCJGooAgAgACgCICACaigCABEFAAwBCwsgACgCHCIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgACgCIBAvIAAoAiQQLyAAKAIwEC8gACgCPBAvIAALIAAgACAAKAIYRSABciIBNgIQIAAoAhQgAXEEQBBGAAsLRgAjAEEQayIBJAAgASADNgIMIAQgAiADIAJrIgL8CgAAIAEgAiAEajYCCCAAIAEoAgw2AgAgACABKAIINgIEIAFBEGokAAs2AQF/IwBBEGsiAyQAIAMgATYCDCADIAI2AgggACADKAIMNgIAIAAgAygCCDYCBCADQRBqJAALOwEBfyAAQfDKAigCACIBNgIAIAAgAUEMaygCAGpB/MoCKAIANgIAIABBCGoQ8gEaIABB7ABqEMACIAALDAAgAEEIahDAAiAACwgAIAAQugIaC9IDAgJ+An8jAEEgayIEJAACQCABQv///////////wCDIgNCgICAgICAwIA8fSADQoCAgICAgMD/wwB9VARAIAFCBIYgAEI8iIQhAyAAQv//////////D4MiAEKBgICAgICAgAhaBEAgA0KBgICAgICAgMAAfCECDAILIANCgICAgICAgIBAfSECIABCgICAgICAgIAIUg0BIAIgA0IBg3whAgwBCyAAUCADQoCAgICAgMD//wBUIANCgICAgICAwP//AFEbRQRAIAFCBIYgAEI8iIRC/////////wODQoCAgICAgID8/wCEIQIMAQtCgICAgICAgPj/ACECIANC////////v//DAFYNAEIAIQIgA0IwiKciBUGR9wBJDQAgBEEQaiAAIAFC////////P4NCgICAgICAwACEIgIgBUGB9wBrEGYgBCAAIAJBgfgAIAVrEK8BIAQpAwhCBIYgBCkDACIAQjyIhCECIAQpAxAgBCkDGIRCAFKtIABC//////////8Pg4QiAEKBgICAgICAgAhaBEAgAkIBfCECDAELIABCgICAgICAgIAIUg0AIAJCAYMgAnwhAgsgBEEgaiQAIAIgAUKAgICAgICAgIB/g4S/C4gCAAJAIAAEfyABQf8ATQ0BAkAjAygCYCgCAEUEQCABQYB/cUGAvwNGDQMMAQsgAUH/D00EQCAAIAFBP3FBgAFyOgABIAAgAUEGdkHAAXI6AABBAg8LIAFBgEBxQYDAA0cgAUGAsANPcUUEQCAAIAFBP3FBgAFyOgACIAAgAUEMdkHgAXI6AAAgACABQQZ2QT9xQYABcjoAAUEDDwsgAUGAgARrQf//P00EQCAAIAFBP3FBgAFyOgADIAAgAUESdkHwAXI6AAAgACABQQZ2QT9xQYABcjoAAiAAIAFBDHZBP3FBgAFyOgABQQQPCwsjA0EcakEZNgIAQX8FQQELDwsgACABOgAAQQEL1AIBBH8jAEHQAWsiBSQAIAUgAjYCzAEgBUGgAWoiAkEAQSj8CwAgBSAFKALMATYCyAECQEEAIAEgBUHIAWogBUHQAGogAiADIAQQiQRBAEgEQEF/IQQMAQsgACgCTEEATgRAIAAQggEhBgsgACAAKAIAIghBX3E2AgACfwJAAkAgACgCMEUEQCAAQdAANgIwIABBADYCHCAAQgA3AxAgACgCLCEHIAAgBTYCLAwBCyAAKAIQDQELQX8gABDSAg0BGgsgACABIAVByAFqIAVB0ABqIAVBoAFqIAMgBBCJBAshAiAHBEAgAEEAQQAgACgCJBEDABogAEEANgIwIAAgBzYCLCAAQQA2AhwgACgCFCEBIABCADcDECACQX8gARshAgsgACAAKAIAIgEgCEEgcXI2AgBBfyACIAFBIHEbIQQgBkUNACAAEIEBCyAFQdABaiQAIAQLugQCBH0CfwJAAkACQAJ9AkAgALwiBkH/////B3EiBUHE8NaMBE8EQCAFQYCAgPwHSw0FIAZBAEgEQEMAAIC/DwsgBUGY5MWVBEkNASAAQwAAAH+UDwsgBUGZ5MX1A0kNAiAFQZGrlPwDSw0AIAZBAE4EQEEBIQVD0fcXNyEBIABDgHExv5IMAgtBfyEFQ9H3F7chASAAQ4BxMT+SDAELAn8gAEM7qrg/lEMAAAA/IACYkiIBi0MAAABPXQRAIAGoDAELQYCAgIB4CyIFsiICQ9H3FzeUIQEgACACQ4BxMb+UkgsiACAAIAGTIgCTIAGTIQEMAQsgBUGAgICYA0kNAUEAIQULIAAgAEMAAAA/lCIDlCICIAIgAkMQMM86lENoiAi9kpRDAACAP5IiBEMAAEBAIAQgA5STIgOTQwAAwEAgACADlJOVlCEDIAVFBEAgACAAIAOUIAKTkw8LIAAgAyABk5QgAZMgApMhAQJAAkACQCAFQQFqDgMAAgECCyAAIAGTQwAAAD+UQwAAAL+SDwsgAEMAAIC+XQRAIAEgAEMAAAA/kpNDAAAAwJQPCyAAIAGTIgAgAJJDAACAP5IPCyAFQRd0IgZBgICA/ANqviECIAVBOU8EQCAAIAGTQwAAgD+SIgAgAJJDAAAAf5QgACAClCAFQYABRhtDAACAv5IPC0GAgID8AyAGa74hAyAFQRZNBH1DAACAPyADkyAAIAGTkgUgACABIAOSk0MAAIA/kgsgApQhAAsgAAsqAQJ/IwBBEGsiBCQAIAQgAzYCDCAAIAEgAiADELABIQUgBEEQaiQAIAUL2wEBAX8CQEH8ugMoAgAiAEEATgRAIABFDQEjAygCGCAAQf////97cUcNAQsCQEGAuwMoAgBBCkYNAEHEugMoAgAiAEHAugMoAgBGDQBBxLoDIABBAWo2AgAgAEEKOgAADwsQ0QIPC0EAQQBB/////wP+SAL8ugMEQEGwugMQggEaCwJAAkBBgLsDKAIAQQpGDQBBxLoDKAIAIgBBwLoDKAIARg0AQcS6AyAAQQFqNgIAIABBCjoAAAwBCxDRAgtBAEEA/kEC/LoDQYCAgIAEcQRAQfy6A0EBELUBCwt+AQR/Qaz3NCgCACMDKAIYRgRAQaz3NEEANgIACwNAQaT3NCgCACECQaD3NEGg9zQoAgAiACAAQQFrQQAgAEH/////B3EiAUEBRxtBACABQf////8HRxsiA/5IAgAgAEcNAAsCQCADDQAgAkUgAEEATnENAEGg9zQgARC1AQsLUgEDfwJAAkADQEEGIQFBCiECAkBBoPc0KAIAIgBB/////wdxQf7///8Haw4CAwIACyAAQaD3NCAAIABBAWr+SAIARw0AC0EAIQILIAIhAQsgAQs4AQF/QZDzNCgCACIABEBBkPM0IABBAWs2AgAPC0GM8zRBAP4XAgBBlPM0KAIABEBBjPM0EI4BCwtZAQJ/IwMoAhgiAEGM8zQoAgBHBEBBjPM0QQAgAP5IAgAiAQRAA0BBjPM0QZTzNCABEKEBQYzzNEEAIAD+SAIAIgENAAsLDwtBkPM0QZDzNCgCAEEBajYCAAtaAQN/IwBBEGsiAiQAIwMhAyACQQxqIgQEQCAEIAMtACg2AgALIANBAToAKCAAIAEgAhD5ASEFIAIoAgwiAUECTQR/IwMgAToAKEEABUEcCxogAkEQaiQAIAULcAECfyMAQRBrIgEkACAAQQE2AiAgAEEEaiICEFYaIAAoAiwgACgCMEcEQANAIAFBBGogABCfBCACEFIaIAEoAgwgASgCBBEBACACEFYaIAAoAiwgACgCMEcNAAsLIAIQUhogAEEANgIgIAFBEGokAAueDAMGfAN+CH8jAEEQayIOJAACQAJAIAG9IglCNIinIg1B/w9xIg9BvghrIhBB/35LIAC9IghCNIinIgtB/w9rQYJwT3ENACAJQgGGIgpCgICAgICAgBB8QoGAgICAgIAQVARARAAAAAAAAPA/IQIgCEKAgICAgICA+D9RDQIgClANAiAKQoGAgICAgIBwVCAIQgGGIghCgICAgICAgHBYcUUEQCAAIAGgIQIMAwsgCEKAgICAgICA8P8AUQ0CRAAAAAAAAAAAIAEgAaIgCEL/////////7/8AViAJQgBZcxshAgwCCyAIQgGGQoCAgICAgIAQfEKBgICAgICAEFQEQCAAIACiIQIgCEIAUwRAIAKaIAIgCRCkBEEBRhshAgsgCUIAWQ0CIwBBEGsiC0QAAAAAAADwPyACozkDCCALKwMIIQIMAgsgCEIAUwRAIAkQpAQiDEUEQCAAIAChIgAgAKMhAgwDCyALQf8PcSELIAxBAUZBEnQhDCAIQv///////////wCDIQgLIBBB/35NBEBEAAAAAAAA8D8hAiAIQoCAgICAgID4P1ENAiAPQb0HTQRAIAEgAZogCEKAgICAgICA+D9WG0QAAAAAAADwP6AhAgwDCyANQYAQSSAIQoGAgICAgID4P1RHBEAjAEEQayILRAAAAAAAAABwOQMIIAsrAwhEAAAAAAAAAHCiIQIMAwsjAEEQayILRAAAAAAAAAAQOQMIIAsrAwhEAAAAAAAAABCiIQIMAgsgCw0AIABEAAAAAAAAMEOivUL///////////8Ag0KAgICAgICAoAN9IQgLAnwgCUKAgIBAg78iBSEHIA4gCEKAgICA0Kql8z99IglCNIentyIDQdCgAisDAKIgCUItiKdB/wBxQQV0IgtBqKECaisDAKAgCCAJQoCAgICAgIB4g30iCEKAgICACHxCgICAgHCDvyIAIAtBkKECaisDACIEokQAAAAAAADwv6AiAiAIvyAAoSAEoiIEoCIAIANByKACKwMAoiALQaChAmorAwCgIgMgACADoCIDoaCgIAQgAEHYoAIrAwAiBKIiBiACIASiIgSgoqAgAiAEoiICIAMgAyACoCICoaCgIAAgACAGoiIDoiADIAMgAEGIoQIrAwCiQYChAisDAKCiIABB+KACKwMAokHwoAIrAwCgoKIgAEHooAIrAwCiQeCgAisDAKCgoqAiACACIAIgAKAiAqGgOQMIIAcgAr1CgICAQIO/IgOiIQAgASAFoSADoiAOKwMIIAIgA6GgIAGioCEBAkAgAL1CNIinQf8PcSILQckHa0E/SQ0AIAtByQdJBEAgAEQAAAAAAADwP6AiAJogACAMGwwCCyALQYkISSERQQAhCyARDQAgAL1CAFMEQCMAQRBrIgtEAAAAAAAAAJBEAAAAAAAAABAgDBs5AwggCysDCEQAAAAAAAAAEKIMAgsjAEEQayILRAAAAAAAAADwRAAAAAAAAABwIAwbOQMIIAsrAwhEAAAAAAAAAHCiDAELQZjbASsDACAAokGg2wErAwAiAqAiAyACoSICQbDbASsDAKIgAkGo2wErAwCiIACgoCABoCIAIACiIgEgAaIgAEHQ2wErAwCiQcjbASsDAKCiIAEgAEHA2wErAwCiQbjbASsDAKCiIAO9IgmnQQR0QfAPcSINQYjcAWorAwAgAKCgoCEAIA1BkNwBaikDACAJIAytfEIthnwhCCALRQRAAnwgCUKAgICACINQBEAgCEKAgICAgICAiD99vyIBIACiIAGgRAAAAAAAAAB/ogwBCyAIQoCAgICAgIDwP3wiCL8iASAAoiIDIAGgIgCZRAAAAAAAAPA/YwR8IwBBEGsiCyESIAtEAAAAAAAAEAA5AwggEiALKwMIRAAAAAAAABAAojkDCCAIQoCAgICAgICAgH+DvyAARAAAAAAAAPC/RAAAAAAAAPA/IABEAAAAAAAAAABjGyICoCIFIAMgASAAoaAgACACIAWhoKCgIAKhIgAgAEQAAAAAAAAAAGEbBSAAC0QAAAAAAAAQAKILDAELIAi/IgEgAKIgAaALIQILIA5BEGokACACC8EBAQN/AkAgASACKAIQIgMEfyADBSACENICDQEgAigCEAsgAigCFCIFa0sEQCACIAAgASACKAIkEQMADwsCQCACKAJQQQBIBEBBACEDDAELIAEhBANAIAQiA0UEQEEAIQMMAgsgACADQQFrIgRqLQAAQQpHDQALIAIgACADIAIoAiQRAwAiBCADSQ0BIAAgA2ohACABIANrIQEgAigCFCEFCyAFIAAgARB7GiACIAIoAhQgAWo2AhQgASADaiEECyAECzcBAn8gACgCTEEASARAIAAgASACEKkEDwsgABCCASEEIAAgASACEKkEIQIgBARAIAAQgQELIAILfAECfyAAIAAoAkgiAUEBayABcjYCSCAAKAIUIAAoAhxHBEAgAEEAQQAgACgCJBEDABoLIABBADYCHCAAQgA3AxAgACgCACIBQQRxBEAgACABQSByNgIAQX8PCyAAIAAoAiwgACgCMGoiAjYCCCAAIAI2AgQgAUEbdEEfdQuNAQECfyMAQRBrIgAkACAAQQo6AA8CQAJAQcC6AygCACIBBH8gAQVBsLoDENICDQJBwLoDKAIAC0HEugMoAgAiAUYNAEGAuwMoAgBBCkYNAEHEugMgAUEBajYCACABQQo6AAAMAQtBsLoDIABBD2pBAUHUugMoAgARAwBBAUcNACAALQAPGgsgAEEQaiQAC1kBAX8gACAAKAJIIgFBAWsgAXI2AkggACgCACIBQQhxBEAgACABQSByNgIAQX8PCyAAQgA3AgQgACAAKAIsIgE2AhwgACABNgIUIAAgASAAKAIwajYCEEEAC9MBAgF/AnwgAisDICEFAn8CQCABKwMgIgYgACsDIGRFBEBBACAFIAZkRQ0CGiABIAIQPkEBIAErAyAgACsDIGRFDQIaIAAgARA+DAELIAUgBmQEQCAAIAIQPkEBDAILIAAgARA+QQEgAisDICABKwMgZEUNARogASACED4LQQILIQQgAysDICACKwMgZAR/IAIgAxA+IAIrAyAgASsDIGRFBEAgBEEBag8LIAEgAhA+IAErAyAgACsDIGRFBEAgBEECag8LIAAgARA+IARBA2oFIAQLC34BAX8gACABIAIgAxDTAiEFIAQrAyAgAysDIGQEfyADIAQQPiADKwMgIAIrAyBkRQRAIAVBAWoPCyACIAMQPiACKwMgIAErAyBkRQRAIAVBAmoPCyABIAIQPiABKwMgIAArAyBkRQRAIAVBA2oPCyAAIAEQPiAFQQRqBSAFCwtIAQF/IABBwLMBNgIAIAAoAggiAQRAIAEgASgCACgCBBEBAAsgAEHcqQE2AgAgACgCBCIBBEAgASABKAIAKAIEEQEACyAAEC8L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A0AgBEEEayIEIAFBBGsiASgCADYCACABIAZHDQALCyAHIA0gCyANayIB/AoAACAAIAU2AgggACABIAdqNgIEIAAgBDYCACAGBEAgBhAvCwsPCxA2AAsQRwALIAohBSAEIQELA0AgASAFKAIANgIAIAFBBGohASAFQQRqIgUgC0kNAAsLIAAgATYCBCAEIAlBAnRrIA0gCPwKAAAgDSACIAcgAmv8CgAAC+kaAgl/A3wjAEEQayIDJAADQCABQRBrIQcDQCAAIQQDQAJAAkACQAJAAkACQAJAAkAgASAEayIIQQR1IgkOBgcHAAEEAgMLIAFBEGsiACsDACAEKwMAZEUNBiADIAT9AAMA/QsDACAEIAAoAgg2AgggBCAAKQMANwMAIAAgAygCCDYCCCAAIAMpAwA3AwAMBgsgBEEQaiEAIAFBEGsiASsDACEMIAQrAxAiDSAEKwMAZEUEQCAMIA1kRQ0GIAMgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASADKAIINgIIIAEgAykDADcDACAEKwMQIAQrAwBkRQ0GIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDAAwGCyAMIA1kBEAgAyAE/QADAP0LAwAgBCABKAIINgIIIAQgASkDADcDACABIAMoAgg2AgggASADKQMANwMADAYLIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDACABKwMAIAQrAxBkRQ0FIAMgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASADKAIINgIIIAEgAykDADcDAAwFCyAEIARBEGoiAiAEQSBqIgAgBEEwaiIFENgBGiABQRBrIgErAwAgBCsDMGRFDQQgAyAF/QADAP0LAwAgBSABKAIINgIIIAUgASkDADcDACABIAMoAgg2AgggASADKQMANwMAIAUrAwAgACsDAGRFDQQgAyAA/QADAP0LAwAgACAFKAIINgIIIAAgBSkDADcDACAFIAMoAgg2AgggBSADKQMANwMAIAArAwAgAisDAGRFDQQgAyAC/QADAP0LAwAgAiAAKAIINgIIIAIgACkDADcDACAAIAMoAgg2AgggACADKQMANwMAIAQrAxAgBCsDAGRFDQQgAyAE/QADAP0LAwAgBCACKAIINgIIIAQgAikDADcDACACIAMoAgg2AgggAiADKQMANwMADAQLIAhB7wNMBEAgBEEQaiEAIARBIGohBSAEKwMgIQwCQCAEKwMQIg0gBCsDACIOZEUEQCAMIA1kRQ0BIAMgAP0AAwD9CwMAIAAgBUEIaigCADYCCCAAIAUpAwA3AwAgBSADKAIINgIIIAUgAykDADcDACAAKwMAIA5kRQ0BIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDAAwBCyAMIA1kBEAgAyAE/QADAP0LAwAgBCAFQQhqKAIANgIIIAQgBSkDADcDACAFIAMoAgg2AgggBSADKQMANwMADAELIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDACAMIAQrAxBkRQ0AIAMgAP0AAwD9CwMAIAAgBUEIaigCADYCCCAAIAUpAwA3AwAgBSADKAIINgIIIAUgAykDADcDAAsgBEEwaiIGIAFGDQQDQCAGKwMAIgwgBSsDAGQEQCAGKAIIIQcgBiECA0ACQCACIAUiACkDADcDACACIAAoAgg2AgggACAERgRAIAQhAAwBCyAAIQIgDCAAQRBrIgUrAwBkDQELCyAAIAc2AgggACAMOQMACyAGIgVBEGoiACEGIAAgAUcNAAsMBAsgAkUEQCABIARGDQQgCUECa0EBdiIKIQADQAJAIAogACIHSA0AIAQgAEEEdGohBSAEIABBAXQiAkEBciIGQQR0aiEAAkAgCSACQQJqIgJMBEAgBiECDAELIAArAwAgACsDEGRFBEAgBiECDAELIABBEGohAAsgBSsDACIMIAArAwBjDQAgBSgCCCELA0ACQCAFIgYgACIFKQMANwMAIAYgACgCCDYCCCACIApKDQAgBCACQQF0IgJBAXIiBkEEdGohAAJAIAkgAkECaiICTARAIAYhAgwBCyAAKwMAIAArAxBkRQRAIAYhAgwBCyAAQRBqIQALIAArAwAgDGRFDQELCyAFIAs2AgggBSAMOQMACyAHQQFrIQAgB0EASg0ACyAIQQR2IQADQCADIAT9AAMA/QsDACAAIgdBAmtBAXYhCUEAIQIgBCEAA0AgAkEBdCIIQQFyIQUgACIGIAJBBHRqQRBqIQACQCAHIAhBAmoiAkwEQCAFIQIMAQsgACsDACAAKwMQZEUEQCAFIQIMAQsgAEEQaiEACyAGIAApAwA3AwAgBiAAQQhqKAIANgIIIAIgCUwNAAsCQCABQRBrIgEgAEYEQCAAIAMpAwA3AwAgACADKAIINgIIDAELIAAgASkDADcDACAAIAFBCGooAgA2AgggASADKQMANwMAIAEgAygCCDYCCCAAIARrQRBqIgJBEUgNACAAKwMAIgwgBCACQQR2QQJrQQF2IgZBBHRqIggrAwBjRQ0AIAAoAgghBQNAAkAgACAIIgIpAwA3AwAgACACKAIINgIIIAZFDQAgAiEAIAQgBkEBa0EBdiIGQQR0aiIIKwMAIAxkDQELCyACIAU2AgggAiAMOQMACyAHQQFrIQAgB0ECSg0ACwwECyAEIAlBA3RBcHFqIQYCQCAIQfH8AE8EQCAEIAQgCUECdEFwcSIFaiIAIAYgBSAGaiIFENgBIQggBysDACAFKwMAZEUNASADIAX9AAMA/QsDACAFIAcoAgg2AgggBSAHKQMANwMAIAcgAygCCDYCCCAHIAMpAwA3AwAgBSsDACAGKwMAZEUEQCAIQQFqIQgMAgsgAyAG/QADAP0LAwAgBkEIaiAFKAIINgIAIAYgBSkDADcDACAFIAMoAgg2AgggBSADKQMANwMAIAYrAwAgACsDAGRFBEAgCEECaiEIDAILIAMgAP0AAwD9CwMAIAAgBigCCDYCCCAAIAYpAwA3AwAgBiADKAIINgIIIAYgAykDADcDACAAKwMAIAQrAwBkRQRAIAhBA2ohCAwCCyADIAT9AAMA/QsDACAEIAAoAgg2AgggBCAAKQMANwMAIAAgAygCCDYCCCAAIAMpAwA3AwAgCEEEaiEIDAELIAcrAwAhDAJAIAYrAwAiDSAEKwMAZEUEQEEAIQggDCANZEUNAiADIAb9AAMA/QsDACAGQQhqIAcoAgg2AgAgBiAHKQMANwMAIAcgAygCCDYCCCAHIAMpAwA3AwBBASEIIAYrAwAgBCsDAGRFDQIgAyAE/QADAP0LAwAgBCAGKAIINgIIIAQgBikDADcDACAGIAMoAgg2AgggBiADKQMANwMADAELIAwgDWQEQCADIAT9AAMA/QsDACAEIAcoAgg2AgggBCAHKQMANwMAIAcgAygCCDYCCCAHIAMpAwA3AwBBASEIDAILIAMgBP0AAwD9CwMAIAQgBkEIaigCADYCCCAEIAYpAwA3AwAgBiADKAIINgIIIAYgAykDADcDAEEBIQggBysDACAGKwMAZEUNASADIAb9AAMA/QsDACAGIAcoAgg2AgggBiAHKQMANwMAIAcgAygCCDYCCCAHIAMpAwA3AwALQQIhCAsgAkEBayECIAchACAEKwMAIgwgBisDACINZEUEQANAIABBEGsiACAERgRAIARBEGohBSAMIAcrAwBkDQUgBSAHRg0GA0AgBSsDACAMYwRAIAMgBf0AAwD9CwMAIAUgBygCCDYCCCAFIAcpAwA3AwAgByADKAIINgIIIAcgAykDADcDACAFQRBqIQUMBwsgBUEQaiIFIAdHDQALDAYLIAArAwAgDWRFDQALIAMgBP0AAwD9CwMAIAQgAEEIaigCADYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDACAIQQFqIQgLIARBEGoiBSAATw0BA0AgBisDACEMA0AgBSIJQRBqIQUgCSsDACAMZA0ACwNAIABBEGsiACsDACAMZEUNAAsgACAJSQRAIAkhBQwDBSADIAn9AAMA/QsDACAJIABBCGooAgA2AgggCSAAKQMANwMAIAAgAygCCDYCCCAAIAMpAwA3AwAgACAGIAYgCUYbIQYgCEEBaiEIDAELAAsACyAEIARBEGogBEEgaiABQRBrENgBGgwCCwJAIAUgBkYNACAGKwMAIAUrAwBkRQ0AIAMgBf0AAwD9CwMAIAUgBkEIaigCADYCCCAFIAYpAwA3AwAgBiADKAIINgIIIAYgAykDADcDACAIQQFqIQgLIAhFBEAgBCAFELIEIQYgBUEQaiIAIAEQsgQEQCAEIQAgBSEBIAZFDQYMAwsgBg0ECyAFIARrIAEgBWtIBEAgBCAFIAIQ6wIgBUEQaiEADAQLIAVBEGogASACEOsCIAQhACAFIQEMBAsgByIAIAVGDQADQCAEKwMAIQwDQCAFIgZBEGohBSAMIAYrAwBkRQ0ACwNAIAwgAEEQayIAKwMAZA0ACyAAIAZNBEAgBiEEDAMFIAMgBv0AAwD9CwMAIAYgAEEIaigCADYCCCAGIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDAAwBCwALAAsLCwsgA0EQaiQACwkAQcEdELcBAAuSCQEEf0EEEDIiBEHspQE2AgBBCBAyIgNByKgBNgIAIAMgBDYCBEEQEDIiBCADNgIMIARBxKYBNgIAIARCADcCBCAAIAM2AhwgACgCICEDIAAgBDYCIAJAIANFDQAgA0F//h4CBA0AIAMgAygCACgCCBEBAAJAIANBCGoiBP4QAgAEQCAEQX/+HgIADQELIAMgAygCACgCEBEBAAsLIAAgACgCHDYCJAJAAkACQAJAIAAoAgxB8AdxIgNB/wBNBEAgA0EQaw4RAwICAgICAgICAgICAgICAgQBCwJAIANBgAFHBEAgA0GAAkYNASADQYAERw0DIAAgASACEOUCDwsgACIDKAIkIQYCQAJAIAEgAkYNACABIQACQANAIAAtAABBCkYNASAAQQFqIgAgAkcNAAsgAiEACyAAIAFGDQAgAyABIAAQ5AIaIAAhAQwBC0EIEDIhACAGKAIEIQQgAEHIqAE2AgAgACAENgIEIAYgADYCBCADIAMoAiQoAgQ2AiQLIAIgASABIAJHaiIBRwRAA0AgASEAAkADQCAALQAAQQpGDQEgAEEBaiIAIAJHDQALIAIhAAsgAygCJCEEAkAgACABRwRAIAMgASAAEOQCGgwBC0EIEDIhASAEKAIEIQUgAUHIqAE2AgAgASAFNgIEIAQgATYCBCADIAMoAiQoAgQ2AiQLQQwQMiEBIAYoAgQhBSABIAQoAgQ2AgggASAFNgIEIAFBnLQBNgIAIAYgATYCBCAEQQA2AgRBCBAyIQEgAygCJCgCBCEFIAFByKgBNgIAIAEgBTYCBCAEIAE2AgQgAygCJEEANgIEQQgQMiEBIAQoAgQhBSABQdy0ATYCACABIAU2AgQgAygCJCABNgIEIAMgBCgCBDYCJCAAIAAgAkdqIgEgAkcNAAsLIAIPCyAAIgMoAiQhBgJAAkAgASACRg0AIAEhAAJAA0AgAC0AAEEKRg0BIABBAWoiACACRw0ACyACIQALIAAgAUYNACADIAEgABCGAhogACEBDAELQQgQMiEAIAYoAgQhBCAAQcioATYCACAAIAQ2AgQgBiAANgIEIAMgAygCJCgCBDYCJAsgAiABIAEgAkdqIgFHBEADQCABIQACQANAIAAtAABBCkYNASAAQQFqIgAgAkcNAAsgAiEACyADKAIkIQQCQCAAIAFHBEAgAyABIAAQhgIaDAELQQgQMiEBIAQoAgQhBSABQcioATYCACABIAU2AgQgBCABNgIEIAMgAygCJCgCBDYCJAtBDBAyIQEgBigCBCEFIAEgBCgCBDYCCCABIAU2AgQgAUGctAE2AgAgBiABNgIEIARBADYCBEEIEDIhASADKAIkKAIEIQUgAUHIqAE2AgAgASAFNgIEIAQgATYCBCADKAIkQQA2AgRBCBAyIQEgBCgCBCEFIAFB3LQBNgIAIAEgBTYCBCADKAIkIAE2AgQgAyAEKAIENgIkIAAgACACR2oiASACRw0ACwsgAg8LIANBwABGDQILQQwQXkEOEHBB0KkDQdIAEAIACyAAIAEgAhDkAg8LIAAgASACEIYCC/gLAhF/AX4jAEEQayINJAAQaSEXAn8CQAJAIAIoAgAiCiABKAJQIgtNBEAgACgCICEQIAEoAlghCSABKAJMIQwgCkUNAQNAQQAhBiALIAogDGpJBEAgAUEANgJMIAsgDGsgCGohCEEAIQwMAQsCQANAIAZBAWohByAJIAYgDGpBBHRqKAIAQQBODQEgByIGIApHDQALIAIoAgwhCANAIAwgEWpBBHQiFSABKAJYaiARQQJ0IhIgAigCCGooAgA2AgBBACETIAggEmooAgBBAEoEQANAIAIoAhAgEmooAgAgE0ECdGooAgAhFCABKAJYIBVqIg9BCGoiDiEJAkACQCAOIgYoAgAiB0UNAANAIAciBigCECIHIBRKBEAgBiEJIAYoAgAiBw0BDAILIAcgFE4NAiAGKAIEIgcNAAsgBkEEaiEJC0EUEDIiCCAGNgIIIAhCADcCACAIIBQ2AhAgCSAINgIAIA8oAgQoAgAiBgRAIA8gBjYCBCAJKAIAIQgLIAggCCAOKAIAIg5GIgY6AAwCQCAGDQADQCAIKAIIIgctAAwNAQJAIAcgBygCCCIGKAIAIglGBEACQCAGKAIEIglFDQAgCS0ADA0ADAILAkAgCCAHKAIARgRAIAchCQwBCyAHIAcoAgQiCSgCACIINgIEIAkgCAR/IAggBzYCCCAHKAIIBSAGCzYCCCAHKAIIIgYgBigCACAHR0ECdGogCTYCACAJIAc2AgAgByAJNgIIIAkoAggiBigCACEHCyAJQQE6AAwgBkEAOgAMIAYgBygCBCIINgIAIAgEQCAIIAY2AggLIAcgBigCCDYCCCAGKAIIIgggCCgCACAGR0ECdGogBzYCACAHIAY2AgQgBiAHNgIIDAMLAkAgCUUNACAJLQAMDQAMAQsCQCAIIAcoAgBHBEAgByEIDAELIAcgCCgCBCIJNgIAIAggCQR/IAkgBzYCCCAHKAIIBSAGCzYCCCAHKAIIIgYgBigCACAHR0ECdGogCDYCACAIIAc2AgQgByAINgIIIAgoAgghBgsgCEEBOgAMIAZBADoADCAGIAYoAgQiBygCACIINgIEIAgEQCAIIAY2AggLIAcgBigCCDYCCCAGKAIIIgggCCgCACAGR0ECdGogBzYCACAHIAY2AgAgBiAHNgIIDAILIAdBAToADCAGIAYgDkY6AAwgCUEBOgAMIA4gBiIIRw0ACwsgDyAPKAIMQQFqNgIMIAIoAgwhCAsgE0EBaiITIAggEmooAgBIDQALCyARQQFqIhEgCkcNAAsgASgCWCEJDAQLIAEgByAMaiIMNgJMIAcgCGoiCCALSQ0AC0EADAMLIA0gCzYCCCANIAo2AgQgDUGKCzYCAEECQbvqACANEDRBAAwCCyALIAxPDQAgAUEANgJMCwJAIAtBAWsiBgRAA0AgCSAGQQR0aiIHKAIAQQBOBEAgBygCDA0DCyAGIgtBAWsiBg0ACwtBASELCyABIAs2AlQgASgC0KcBEJICIAAgASACENoEIQYgASgC0KcBIAYQ2gEgBigCDCAGKAIEQQJ0akEEaygCACEHIAEoApCnASIAKAIAQTxGBEAgACADEJECCyABQYSoAWohAyAAIAYgACgCLBECACAAKAIcIgYEQCAAIAYRAQALAkAgCiAQbCIAIAFBiKgBaigCACABKAKEqAEiCGtBAnUiBksEQCADIAAgBmsQbgwBCyAAIAZPDQAgASAIIABBAnRqNgKIqAELIApBAEoEQCAQQQJ0IQBBACEGA0AgAigCFCAGai0AAARAIAcgBiAQbEECdCIIIAMoAgBqIAggABDmBAsgBkEBaiIGIApHDQALCwJAIAIoAgAiAEEBRgRAIAEQaSAXfSABKQMQfDcDECABIAEoAjhBAWo2AjgMAQsQaSAXfSEXIABBD0wEQCABIBcgASkDGHw3AxggASABKAI8IApqNgI8DAELIAEgFyABKQMgfDcDICABIAEoAkAgCmo2AkALQQEgBEUNABogBSAEEQAAQQFzCyEWIA1BEGokACAWC7oNAQx/AkAgACgCBCIDRQ0AIAJBACACQQBKGyEMIAAoAgwhBwJAIAFBAEgEQCADIQgDQAJAIAcgCUEEdCICaiIBKAIAIgUgDEgNACAFQf////8HRg0AIAFBBGogAUEIaiIDKAIAEJYBIAEgAzYCBCABQgA3AgggACgCBCEDIAAoAgwiByACaiIBKAIMDQAgAUF/NgIAIAkgCCADIAhGGyEICyAJQQFqIgkgA0kNAAsMAQsgAyEIA0ACQCAHIAlBBHQiDWoiBigCACICIAxIDQAgAkH/////B0YNACAGQQhqIgohBCAKKAIAIgUhAiAFRQ0AA0AgBCACIAIoAhAgAUgiCxshBCACQQRqIAIgCxsoAgAiAg0ACyAEIApGDQAgBCgCECABSg0AIAZBCGoiCiEEIAUhAgNAIAQgAiACKAIQIAFIIgsbIQQgAkEEaiACIAsbKAIAIgINAAsCQCAEIApGDQAgBCgCECABSg0AAkAgBCIDKAIEIgcEQANAIAciAigCACIHDQAMAgsACwNAIAMoAggiAigCACADRyEOIAIhAyAODQALCyAEIAYoAgRGBEAgBiACNgIECyAGIAYoAgxBAWs2AgwCfwJAIAQiByIDKAIAIgQEQCADKAIEIgJFDQEDQCACIgMoAgAiAg0ACwsgAygCBCIEDQBBACEEQQEMAQsgBCADKAIINgIIQQALIQoCQCADIAMoAggiBigCACICRgRAIAYgBDYCACADIAVGBEBBACECIAQhBQwCCyAGKAIEIQIMAQsgBiAENgIECyADLQAMIQsgAyAHRwRAIAMgBygCCCIGNgIIIAYgBygCCCgCACAHR0ECdGogAzYCACADIAcoAgAiBjYCACAGIAM2AgggAyAHKAIEIgY2AgQgBgRAIAYgAzYCCAsgAyAHLQAMOgAMIAMgBSAFIAdGGyEFCwJAIAtFDQAgBUUNACAKBEADQCACLQAMIQQCQCACIAIoAggiAygCAEcEQCAERQRAIAJBAToADCADQQA6AAwgAyADKAIEIgQoAgAiBjYCBCAGBEAgBiADNgIICyAEIAMoAgg2AgggAygCCCIGIAYoAgAgA0dBAnRqIAQ2AgAgBCADNgIAIAMgBDYCCCACIAUgBSACKAIAIgJGGyEFIAIoAgQhAgsCQAJAAkACQCACKAIAIgMEQCADLQAMRQ0BCyACKAIEIgQEQCAELQAMRQ0CCyACQQA6AAwCQCAFIAIoAggiAkYEQCAFIQIMAQsgAi0ADA0GCyACQQE6AAwMCAsgAigCBCIERQ0BCyAELQAMDQAgAiEDDAELIANBAToADCACQQA6AAwgAiADKAIEIgU2AgAgBQRAIAUgAjYCCAsgAyACKAIINgIIIAIoAggiBSAFKAIAIAJHQQJ0aiADNgIAIAMgAjYCBCACIAM2AgggAiEECyADIAMoAggiAi0ADDoADCACQQE6AAwgBEEBOgAMIAIgAigCBCIDKAIAIgU2AgQgBQRAIAUgAjYCCAsgAyACKAIINgIIIAIoAggiBSAFKAIAIAJHQQJ0aiADNgIAIAMgAjYCACACIAM2AggMBAsgBEUEQCACQQE6AAwgA0EAOgAMIAMgAigCBCIENgIAIAQEQCAEIAM2AggLIAIgAygCCDYCCCADKAIIIgQgBCgCACADR0ECdGogAjYCACACIAM2AgQgAyACNgIIIAIgBSADIAVGGyEFIAMoAgAhAgsCQAJAIAIoAgAiBEUNACAELQAMDQAgAiEDDAELAkAgAigCBCIDBEAgAy0ADEUNAQsgAkEAOgAMIAIoAggiAi0ADEEAIAIgBUcbDQIgAkEBOgAMDAULIAQEQCAELQAMRQRAIAIhAwwCCyACKAIEIQMLIANBAToADCACQQA6AAwgAiADKAIAIgU2AgQgBQRAIAUgAjYCCAsgAyACKAIINgIIIAIoAggiBSAFKAIAIAJHQQJ0aiADNgIAIAMgAjYCACACIAM2AgggAiEECyADIAMoAggiAi0ADDoADCACQQE6AAwgBEEBOgAMIAIgAigCACIDKAIEIgU2AgAgBQRAIAUgAjYCCAsgAyACKAIINgIIIAIoAggiBSAFKAIAIAJHQQJ0aiADNgIAIAMgAjYCBCACIAM2AggMAwsgAigCCCIDIAMoAgAgAkZBAnRqKAIAIQIMAAsACyAEQQE6AAwLIAcQLyAAKAIEIQMgACgCDCEHCyAHIA1qIgIoAgwNACACQX82AgAgCSAIIAMgCEYbIQgLIAlBAWoiCSADSQ0ACwsgAyAIRg0AIAAgCDYCAAsLiwIBB38gAEEEaiEGAkACQCAAKAIEIgBFDQAgASgCACABIAEtAAsiA8BBAEgiAhshBSABKAIEIAMgAhshAyAGIQEDQAJAIAMgACgCFCAALQAbIgIgAsBBAEgiBBsiAiACIANLIgcbIggEQCAAKAIQIABBEGogBBsgBSAIEEoiBA0BC0F/IAcgAiADSRshBAsgASAAIARBAEgiAhshASAAQQRqIAAgAhsoAgAiAA0ACyABIAZGDQACQCABKAIUIAEtABsiACAAwEEASCICGyIAIAMgACADSRsiBARAIAUgASgCECABQRBqIAIbIAQQSiIFDQELIAAgA0sNAQwCCyAFQQBODQELIAYhAQsgAQvOAwELfyABIAAoAggiBCAAKAIEIgJrTQRAIAAgAQR/IAJBACAB/AsAIAEgAmoFIAILNgIEDwsgAiAAKAIAIgVrIgYgAWoiA0EATgRAQf////8HIAQgBWsiBEEBdCIIIAMgAyAISRsgBEH/////A08bIgQEQCAEEDIhBwsgBiAHaiIDQQAgAfwLACAEIAdqIQggASADaiEJAkAgAiAFRgRAIAMhBwwBCwJAAkAgBkEQSQ0AIAUgAiAHamsgAmpBEEkNACADQRBrIQogAkEQayELIAIgBkFwcSIEayECIAMgBGshA0EAIQEDQCAKIAFrIAsgAWv9AAAA/QsAACABQRBqIgEgBEcNAAsgBCAGRg0BCyAFQX9zIAJqIQwgAiAFa0EDcSIEBEBBACEBA0AgA0EBayIDIAJBAWsiAi0AADoAACABQQFqIgEgBEcNAAsLIAxBA0kNAANAIANBAWsgAkEBay0AADoAACADQQJrIAJBAmstAAA6AAAgA0EDayACQQNrLQAAOgAAIANBBGsiAyACQQRrIgItAAA6AAAgAiAFRw0ACwsgACgCACECCyAAIAg2AgggACAJNgIEIAAgBzYCACACBEAgAhAvCw8LEDYAC5AFAQR/IAAoAsyoASIBBEAgAEHQqAFqIAE2AgAgARAvCyAALAC3qAFBAEgEQCAAKAKsqAEQLwsgACgCnKgBIgEEQCAAQaCoAWogATYCACABEC8LIAAoApCoASIDBEAgAEGUqAFqKAIAIgIgAyIBRwRAA0AgAkEwayIBKAIcIgQEQCACQRBrIAQ2AgAgBBAvCyACQRVrLAAAQQBIBEAgAkEgaygCABAvCyABIgIgA0cNAAsgACgCkKgBIQELIAAgAzYClKgBIAEQLwsgACgChKgBIgEEQCAAQYioAWogATYCACABEC8LIAAoAvinASIBBEAgAEH8pwFqIAE2AgAgARAvCyAAKALspwEiAQRAIABB8KcBaiABNgIAIAEQLwsgAEHUpwFqKAIAIgEEQCAAQdinAWogATYCACABEC8LIABBwKcBaigCACIBBEAgAEHEpwFqIAE2AgAgARAvCyAAQaynAWooAgAiAQRAIABBsKcBaiABNgIAIAEQLwsgAEGYpwFqKAIAIgEEQCAAQZynAWogATYCACABEC8LIABBuJIBahClASAAQeD9AGoQpQEgAEGI6QBqEKUBIABBsNQAahClASAAQdg/ahClASAAQYArahClASAAQagWahClASAAQdABahClASAAKAKoASIBBEAgACABNgKsASABEC8LIAAoAoABIgMEQCAAKAKEASICIAMiAUcEQANAIAJBDGsgAkEQayICKAIIEJYBIAIgA0cNAAsgACgCgAEhAQsgACADNgKEASABEC8LIAAoAlgiAwRAIAAoAlwiAiADIgFHBEADQCACQQxrIAJBEGsiAigCCBCWASACIANHDQALIAAoAlghAQsgACADNgJcIAEQLwsgAAtDACABBEAgACABKAIAEPMCIAAgASgCBBDzAiABLAArQQBIBEAgASgCIBAvCyABLAAbQQBIBEAgASgCEBAvCyABEC8LCzEAIAEEQCAAIAEoAgAQ9AIgACABKAIEEPQCIAEsAB9BAEgEQCABKAIUEC8LIAEQLwsLmUgEF34XfwR7AX0jAEGQAWsiIyQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEoAjAiHSABKAIAIhpBJGwiG0GYmwFqKAIARyImDQAgATUCNCIDIAEpAxAgHa1+IBtBlJsBajQCAH9SDQAgATUCOCIFIAEpAxggA35SDQAgATUCPCABKQMgIAV+Ug0AIAIoAjAiGyACKAIAIhxBJGwiIkGYmwFqKAIARw0AIAI1AjQiAyACKQMQIButfiAiQZSbAWo0AgB/Ug0AIAI1AjgiBSACKQMYIAN+Ug0AIBogHEcNACACNQI8IAIpAyAgBX5RDQELAkACQAJAIBoOAgIAAQsgAikDKCIRIAIpAyAiDyACKQMYIhAgAikDECIMfn5+IAEpAygiDSABKQMgIgcgASkDGCIOIAEpAxAiCX5+flEEQAJAIAAoAgAOAw0ADQALIAIoAjwhISACKAI4IR8g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IBogHUcNACAOQgBXDQggDUIAVw0IIBsgHE4NCCAdIAynbCEAIBysIQsgG6whBQNAIB4gBKciGmwhGyAaICRsIRpCACEGA0AgKCAGpyIdbCEcIB0gIGwhHSAFIQMDQCACKALQASAhIAOnIh9saiAdaiAaaiABKALQASAfICJsaiAcaiAbaiAA/AoAACADQgF8IgMgC1INAAsgBkIBfCIGIA1SDQALIA4gBEIBfCIEUg0ACwwICwJAIBogAEEkbCImQZibAWooAgBHDQAgIa0iBSAMIBqtfiAmQZSbAWo0AgAiC39SDQAgIK0iCSAFIBB+Ug0AICStIAkgD35SDQAgHUEERgRAIABFBEAgDkIAVw0KIA1CAFcNCiAbIBxODQogAigC0AEhHSAbIAenQQJ0IgBsISEgHyAcayAAbCEfIBsgImwhJSAcIBtrQQFxISZBACECIBwgG0EBaiInRiEpA0AgHiAIp2whJEIAIQMDQCACICFqIRogKCADp2whICAmBH8gGiAdaiABKALQASAlaiAgaiAkaiAA/AoAACAAIBpqIRogJwUgGwshAiApRQRAA0AgGiAdaiABKALQASACICJsaiAgaiAkaiAA/AoAACAdIAAgGmoiGmogASgC0AEgAkEBaiAibGogIGogJGogAPwKAAAgACAaaiEaIAJBAmoiAiAcRw0ACwsgGiAfaiECIANCAXwiAyANUg0ACyAOIAhCAXwiCFINAAsMCgtBsYAcIAB2QQFxRQRAIAcgC38hAyAOQgBXDQogDUIAVw0KIBsgHE4NCiAAQSRsQaSbAWooAgAhHSACKALQASEkIBogA6dsIhogG2whJSAaIB8gHGtsISYgB6chICAbQQFqIScgGyAibCEpIBwgG2siKkEBcSErQQAhAANAIB4gCKdsISFCACEDA0AgACAlaiECICggA6dsIR8gKwR/IAEoAtABIClqIB9qICFqIAIgJGogICAdEQUAIAIgGmohAiAnBSAbCyEAICpBAUcEQANAIAEoAtABIAAgImxqIB9qICFqIAIgJGogICAdEQUAIAEoAtABIABBAWogImxqIB9qICFqICQgAiAaaiICaiAgIB0RBQAgAiAaaiECIABBAmoiACAcRw0ACwsgAiAmaiEAIANCAXwiAyANUg0ACyAOIAhCAXwiCFINAAsMCgtBvMMCKAIAEDAa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KAIMNgIAIAhBEGokAA8LEE0ACw0AIAAgASABEGgQywELIAAgAEHotQM2AgAgAEHYtgM2AgAgAEEEaiABEIoDIAALPQECfyABEGgiA0ENahAyIgJBADYCCCACIAM2AgQgAiADNgIAIAJBDGoiAiABIANBAWr8CgAAIAAgAjYCAAsSACAAKAIAIAEoAgAQnwFBH3YLgAMCBX8DfiMAQdAAayIDJAACQAJAIAEpAyAiCCACKQMYUQRAIAIpAyhCAVINASACKAIAQRJHDQICfwJAIAEoAogBDQAgAigCiAENAEEADAELQQELIQcgASkDECEJIAIpAxAhCiADIAIpAyA3A0ggAyAINwNAIAMgCjcDOCADIAk3AzAgAEEAQQQgA0EwakEAQQAQSSIEQSI2AkAgBwRAIAAgBCgCACAEKAIMIARBEGpBAEEAEEkhBQsgBCABNgKMASAEIAU2AogBIAQgAjYCkAEgA0HQAGokACAEDwtBvMMCKAIAEDAaIANBkyo2AiggA0GRJTYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxEAAAC0G8wwIoAgAQMBogA0HLPjYCGCADQZIlNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALQbzDAigCABAwGiADQfE7NgIIIANBkyU2AgQgA0HkJjYCAEG4wwIoAgBBy+QAIAMQMRAAAAsMACAAEJQCGiAAEC8LCQAgACABEJQECwcAIAAQUhoLCAAgABCmAhoLFgAgACABIAJCgICAgICAgICAfxDgAwsJACAAEEQ2AgALIwECfyAAIQEDQCABIgJBBGohASACKAIADQALIAIgAGtBAnULBwAgACgCBAswACMAQRBrIgIkAAJAIAAgAUYEQCABQQA6AHgMAQsgAkEPaiABEJsDCyACQRBqJAALJgEBfyAAKAIEIQIDQCABIAJHBEAgAkEEayECDAELCyAAIAE2AgQLSwEBfyMAQRBrIgMkAAJAAkAgAkEeSw0AIAEtAHgNACABQQE6AHgMAQsgA0EPaiACEJ0DIQELIANBEGokACAAIAI2AgQgACABNgIAC18BBX8jAEEQayIAJAAgAEH/////AzYCDCAAQf////8HNgIIIwBBEGsiASQAIABBCGoiAigCACAAQQxqIgMoAgBJIQQgAUEQaiQAIAIgAyAEGygCACEF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AyAAIAJBAWo2AgggAiABQQx2QeABcjoAACAAIAAoAggiAkEBajYCCCACIAFBBnZBP3FBgAFyOgAAIAAgACgCCCICQQFqNgIIIAIgAUE/cUGAAXI6AAALIAAgACgCDEECaiICNgIMDAELC0ECDAILQQEMAQsgBQshCSAEIAAoAgw2AgAgByAAKAIINgIAIABBEGokACAJCz4BA38jAEEQayIBJAAgASAANgIMIAFBCGogAUEMahB/IQNBBEEBIwMoAmAoAgAbIQIgAxB+IAFBEGokACACCzwBAn8jAEEQayIFJAAgBSAENgIMIAVBCGogBUEMahB/IQYgACABIAIgAxDwASEAIAYQfiAFQRBqJAAgAAsSACAEIAI2AgAgByAFNgIAQQMLKAEBfyAAQdzsAjYCAAJAIAAoAggiAUUNACAALQAMRQ0AIAEQLwsgAAsEACABC0ABAn8gACgCACgCACIAKAIAIAAoAggiAkEBdWohASAAKAIEIQAgASACQQFxBH8gASgCACAAaigCAAUgAAsRAQALLgAgASAAQQhqIgAoAgQgACgCACIAa0ECdUkEfyABQQJ0IABqKAIAQQBHBUEACwvLAQEDfyAAQcjsAjYCACAAQQhqIQMDQCACIAAoAgwgACgCCCIBa0ECdUkEQCACQQJ0IAFqKAIAIgEEQCABQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsLIAJBAWohAgwBCwsgAEGYAWoQMxojAEEQayICJAAgAiADNgIMIAIoAgwiASgCBBogASgCCBogASgCABogASgCAARAIAEQsAMgAigCDEEQaiACKAIMIgEoAgAgASgCCCABKAIAa0ECdRCVAwsgAkEQaiQAIAALDAAgACAAKAIAEJYDC3ABAX8jAEEQayICJAAgAiAANgIEIAIgACgCBCIANgIIIAIgACABQQJ0ajYCDCACKAIIIQEgAigCDCEAA0AgACABRgRAIAIoAgQgAigCCDYCBCACQRBqJAAFIAFBADYCACACIAFBBGoiATYCCAwBCwsLIAAgAEGY9QI2AgAgACgCCBBERwRAIAAoAggQ4wMLIAALBABBfwvgAQEIfyMAQRBrIgUkACMAQSBrIgMkACADQRhqIAAgARCaAyADQRBqIANBDGogAygCGCADKAIcIAIQvAIgAygCECEEIwBBEGsiASQAIAEg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DUIANwIAIA1BADYCCCABQRBqJAAjAEEQayIBJAAgC0EkaiIMQgA3AgAgDEEANgIIIAFBEGokACMAQRBrIgEkACALQRhqIhBCADcCACAQQQA2AgggAUEQaiQAIwBBEGsiCiQAIAsCfyACBEAgCkEEaiICIAMQuwMiASABKAIAKAIsEQIAIAsgCigCBDYAXCACIAEgASgCACgCIBECACAMIAIQiAEgAhBQGiACIAEgASgCACgCHBECACANIAIQiAEgAhBQGiALIAEgASgCACgCDBEAADYCWCALIAEgASgCACgCEBEAADYCVCACIAEgASgCACgCFBECACAPIAIQZSACEDMaIAIgASABKAIAKAIYEQIAIA4gAhCIASACEFAaIAEgASgCACgCJBEAAAwBCyAKQQRqIgIgAxC6AyIBIAEoAgAoAiwRAgAgCyAKKAIENgBcIAIgASABKAIAKAIgEQIAIAwgAhCIASACEFAaIAIgASABKAIAKAIcEQIAIA0gAhCIASACEFAaIAsgASABKAIAKAIMEQAANgJYIAsgASABKAIAKAIQEQAANgJUIAIgASABKAIAKAIUEQIAIA8gAhBlIAIQMxogAiABIAEoAgAoAhgRAgAgDiACEIgBIAIQUBogASABKAIAKAIkEQAACzYCFCAKQRBqJAAgCSAIKAIANgIAIARBgARxIRJBACEDQQAhAQNAIAEhAgJAAkACQAJAIANBBEYNACAAIAtBjARqEEINAEEAIQoCQAJAAkACQAJAAkAgC0HcAGogA2osAAAOBQEABAMFCQsgA0EDRg0HIAdBAQJ/IAAoAgAiASgCDCIEIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAQoAgALIAcoAgAoAgwRAwAEQCALQQxqIAAQvAMgECALKAIMEKECDAILIAUgBSgCAEEEcjYCAEEAIQAMBgsgA0EDRg0GCwNAIAAgC0GMBGoQQg0GIAdBAQJ/IAAoAgAiASgCDCIEIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAQoAgALIAcoAgAoAgwRAwBFDQYgC0EMaiAAELwDIBAgCygCDBChAgwACwALAkACfyANLQALQQd2BEAgDSgCBAwBCyANLQALQf8AcQtFDQACfyAAKAIAIgEoAgwiBCABKAIQRgRAIAEgASgCACgCJBEAAAwBCyAEKAIACwJ/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CyADKAIACwJ/IAItAAtBB3YEQCACKAIADAELIAILIApBAnRqKAIARg0BCyAFIAUoAgBBBHI2AgBBACEADAMLIAAQXBogCkEBaiEKDAALAAtBASEAIBEoAgAgCygCZEYNAEEAIQAgC0EANgIMIA8gESgCACALKAJkIAtBDGoQZCALKAIMBEAgBSAFKAIAQQRyNgIADAELQQEhAAsgEBBQGiAMEFAaIA0QUBogDhBQGiAPEDMaIBEoAgAhASARQQA2AgAgAQRAIAEgESgCBBEBAAsMAwsgAiEBCyADQQFqIQMMAAsACyALQZAEaiQAIAALOQECfyABKAIAIQMgAUEANgIAIAAoAgAhAiAAIAM2AgAgAgRAIAIgACgCBBEBAAsgACABKAIENgIECwoAIABBoIk1EHkLCgAgAEGoiTUQeQvkAQEGfyMAQRBrIgUkACAAKAIEIQNBAQJ/IAIoAgAgACgCAGsiBEH/////B0kEQCAEQQF0DAELQX8LIgQgBEEBTRshBCABKAIAIQcgACgCACEIIANB9wFGBH9BAAUgACgCAAsgBBDEASIGBEAgA0H3AUcEQCAAKAIAGiAAQQA2AgALIAVB9gE2AgQgACAFQQhqIAYgBUEEahBRIgMQvgMgAygCACEGIANBADYCACAGBEAgBiADKAIEEQEACyABIAAoAgAgByAIa2o2AgAgAiAEIAAoAgBqNgIAIAVBEGokAA8LEEYACyABAX8gASgCABD9A8AhAiAAIAEoAgA2AgQgACACOgAAC6kZAQl/IwBBkARrIgskACALIAo2AogEIAsgATYCjAQCQCAAIAtBjARqEEMEQCAFIAUoAgBBBHI2AgBBACEADAELIAtB9wE2AkwgCyALQegAaiALQfAAaiALQcwAaiIPEFEiESgCACIBNgJkIAsgAUGQA2o2AmAjAEEQayIBJAAgD0IANwIAIA9BADYCCCABQRBqJAAjAEEQayIBJAAgC0FAayIOQgA3AgAgDkEANgIIIAFBEGokACMAQRBrIgEkACALQTRqIg1CADcCACANQQA2AgggAUEQaiQAIwBBEGsiASQAIAtBKGoiDEIANwIAIAxBADYCCCABQRBqJAAjAEEQayIBJAAgC0EcaiIQQgA3AgAgEEEANgIIIAFBEGokACMAQRBrIgokACALAn8gAgRAIApBBGoiAiADEMAD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fHwhFiAOIAhBAEdqIQ4LIAFBAWohBCABLQABIgENAQwICwsgBSEADAELQQEhB0EAIQpBACEADAILIAwhBwwDCyAMIQcLIA4NAQtBfyEOCyAHRQ0AIAoQLyAAEC8LIBEEQCADEIEBCyAGQbACaiQAIANBkAFqJAAgDgtDAAJAIABFDQACQAJAAkACQCABQQJqDgYAAQICBAMECyAAIAI8AAAPCyAAIAI9AQAPCyAAIAI+AgAPCyAAIAI3AwALC7UDAgN/AX4jAEEgayIDJAACQCABQv///////////wCDIgVCgICAgICAwMA/fSAFQoCAgICAgMC/wAB9VARAIAFCGYinIQQgAFAgAUL///8PgyIFQoCAgAhUIAVCgICACFEbRQRAIARBgYCAgARqIQIMAgsgBEGAgICABGohAiAAIAVCgICACIWEQgBSDQEgAiAEQQFxaiECDAELIABQIAVCgICAgICAwP//AFQgBUKAgICAgIDA//8AURtFBEAgAUIZiKdB////AXFBgICA/gdyIQIMAQtBgICA/AchAiAFQv///////7+/wABWDQBBACECIAVCMIinIgRBkf4ASQ0AIANBEGogACABQv///////z+DQoCAgICAgMAAhCIFIARBgf4AaxBmIAMgACAFQYH/ACAEaxCvASADKQMIIgBCGYinIQIgAykDACADKQMQIAMpAxiEQgBSrYQiBVAgAEL///8PgyIAQoCAgAhUIABCgICACFEbRQRAIAJBAWohAgwBCyAFIABCgICACIWEQgBSDQAgAkEBcSACaiECCyADQSBqJAAgAiABQiCIp0GAgICAeHFyvguNBAIFfwF+AkACQAJAAkACQAJ/IAAoAgQiAiAAKAJoRwRAIAAgAkEBajYCBCACLQAADAELIAAQPwsiAkEraw4DAAEAAQsgAkEtRiEFAn8gACgCBCIDIAAoAmhHBEAgACADQQFqNgIEIAMtAAAMAQsgABA/CyIDQTprIQQgAUUNASAEQXVLDQEgACkDcEIAUw0CIAAgACgCBEEBazYCBAwCCyACQTprIQQgAiEDCyAEQXZJDQACQCADQTBrQQpPDQBBACECA0AgAyACQQpsaiEGAn8gACgCBCICIAAoAmhHBEAgACACQQFqNgIEIAItAAAMAQsgABA/CyEDIAZBMGshAiACQcyZs+YASCADQTBr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IwNBHGpBxAA2AgALIARB8AJqIBcgFiAPEO0DIAQpA/gCIRUgBCkD8AILIRYgDiAVNwMoIA4gFjcDICAEQZDGAGokACAOKQMoIRUgDikDICEWDAQLIAEpA3BCAFkEQCABIAEoAgRBAWs2AgQLDAELAkACfyABKAIEIgIgASgCaEcEQCABIAJBAWo2AgQgAi0AAAwBCyABED8LQShGBEBBASEGDAELQoCAgICAgOD//wAhFSABKQNwQgBTDQMgASABKAIEQQFrNgIEDAMLA0ACfyABKAIEIgIgASgCaEcEQCABIAJBAWo2AgQgAi0AAAwBCyABED8LIglBwQBrIQICQAJAIAlBMGtBCkkNACACQRpJDQAgCUHfAEYNACAJQeEAa0EaTw0BCyAGQQFqIQYMAQsLQoCAgICAgOD//wAhFSAJQSlGDQIgASkDcCIYQgBZBEAgASABKAIEQQFrNgIECwJAIAMEQCAGDQEMBAsMAQsDQCAYQgBZBEAgASABKAIEQQFrNgIECyAGQQFrIgYNAAsMAgsjA0EcakEcNgIAIAFCABCAAQtCACEVCyAAIBY3AwAgACAVNwMIIA5BMGokAAvKBgIFfwR+IwBBgAFrIgUkAAJAAkACQCADIARCAEIAEK4BRQ0AAn8gBEL///////8/gyELAn8gBEIwiKdB//8BcSIGQf//AUcEQEEEIAYNARpBAkEDIAMgC4RQGwwCCyADIAuEUAsLIQkgAkIwiKciCEH//wFxIgdB//8BRg0AIAkNAQsgBUEQaiABIAIgAyAEEEsgBSAFKQMQIgIgBSkDGCIBIAIgARDsAyAFKQMIIQIgBSkDACEEDAELIAEgAkL///////////8AgyILIAMgBEL///////////8AgyIKEK4BQQBMBEAgASALIAMgChCuAQRAIAEhBAwCCyAFQfAAaiABIAJCAEIAEEsgBSkDeCECIAUpA3AhBAwBCyAEQjCIp0H//wFxIQYgBwR+IAEFIAVB4ABqIAEgC0IAQoCAgICAgMC7wAAQSyAFKQNoIgtCMIinQfgAayEHIAUpA2ALIQQgBkUEQCAFQdAAaiADIApCAEKAgICAgIDAu8AAEEsgBSkDWCIKQjCIp0H4AGshBiAFKQNQIQMLIApC////////P4NCgICAgICAwACEIQwgC0L///////8/g0KAgICAgIDAAIQhCyAGIAdIBEADQAJ+IAsgDH0gAyAEVq19IgpCAFkEQCAKIAQgA30iBIRQBEAgBUEgaiABIAJCAEIAEEsgBSkDKCECIAUpAyAhBAwFCyAKQgGGIARCP4iEDAELIAtCAYYgBEI/iIQLIQsgBEIBhiEEIAdBAWsiByAGSg0ACyAGIQcLAkAgCyAMfSADIARWrX0iCkIAUwRAIAshCgwBCyAKIAQgA30iBIRCAFINACAFQTBqIAEgAkIAQgAQSyAFKQM4IQIgBSkDMCEEDAELIApC////////P1gEQANAIARCP4ghDSAHQQFrIQcgBEIBhiEEIA0gCkIBhoQiCkKAgICAgIDAAFQNAAsLIAhBgIACcSEGIAdBAEwEQCAFQUBrIAQgCkL///////8/gyAHQfgAaiAGcq1CMIaEQgBCgICAgICAwMM/EEsgBSkDSCECIAUpA0AhBAwBCyAKQv///////z+DIAYgB3KtQjCGhCECCyAAIAQ3AwAgACACNwMIIAVBgAFqJAALqg8CBX8PfiMAQdACayIFJAAgBEL///////8/gyELIAJC////////P4MhCiACIASFQoCAgICAgICAgH+DIQ0gBEIwiKdB//8BcSEIAkACQCACQjCIp0H//wFxIglB//8Ba0GCgH5PBEAgCEH//wFrQYGAfksNAQsgAVAgAkL///////////8AgyIMQoCAgICAgMD//wBUIAxCgICAgICAwP//AFEbRQRAIAJCgICAgICAIIQhDQwCCyADUCAEQv///////////wCDIgJCgICAgICAwP//AFQgAkKAgICAgIDA//8AURtFBEAgBEKAgICAgIAghCENIAMhAQwCCyABIAxCgICAgICAwP//AIWEUARAIAMgAkKAgICAgIDA//8AhYRQBEBCACEBQoCAgICAgOD//wAhDQwDCyANQoCAgICAgMD//wCEIQ1CACEBDAILIAMgAkKAgICAgIDA//8AhYRQBEBCACEBDAILIAEgDIRQBEBCgICAgICA4P//ACANIAIgA4RQGyENQgAhAQwCCyACIAOEUARAIA1CgICAgICAwP//AIQhDUIAIQEMAgsgDEL///////8/WARAIAVBwAJqIAEgCiABIAogClAiBht5IAZBBnStfKciBkEPaxBmQRAgBmshBiAFKQPIAiEKIAUpA8ACIQELIAJC////////P1YNACAFQbACaiADIAsgAyALIAtQIgcbeSAHQQZ0rXynIgdBD2sQZiAGIAdqQRBrIQYgBSkDuAIhCyAFKQOwAiEDCyAFQaACaiALQoCAgICAgMAAhCISQg+GIANCMYiEIgJCAEKAgICAsOa8gvUAIAJ9IgRCABBgIAVBkAJqQgAgBSkDqAJ9QgAgBEIAEGAgBUGAAmogBSkDmAJCAYYgBSkDkAJCP4iEIgRCACACQgAQYCAFQfABaiAEQgBCACAFKQOIAn1CABBgIAVB4AFqIAUpA/gBQgGGIAUpA/ABQj+IhCIEQgAgAkIAEGAgBUHQAWogBEIAQgAgBSkD6AF9QgAQYCAFQcABaiAFKQPYAUIBhiAFKQPQAUI/iIQiBEIAIAJCABBgIAVBsAFqIARCAEIAIAUpA8gBfUIAEGAgBUGgAWogAkIAIAUpA7gBQgGGIAUpA7ABQj+IhEIBfSICQgAQYCAFQZABaiADQg+GQgAgAkIAEGAgBUHwAGogAkIAQgAgBSkDqAEgBSkDoAEiDCAFKQOYAXwiBCAMVK18IARCAVatfH1CABBgIAVBgAFqQgEgBH1CACACQgAQYCAGIAkgCGtqIQYCfyAFKQNwIhNCAYYiDiAFKQOIASIPQgGGIAUpA4ABQj+IhHwiEELn7AB9IhRCIIgiAiAKQoCAgICAgMAAhCIVQgGGIhZCIIgiBH4iESABQgGGIgxCIIgiCyAQIBRWrSAOIBBWrSAFKQN4QgGGIBNCP4iEIA9CP4h8fHxCAX0iE0IgiCIQfnwiDiARVK0gDiAOIBNC/////w+DIhMgAUI/iCIXIApCAYaEQv////8PgyIKfnwiDlatfCAEIBB+fCAEIBN+IhEgCiAQfnwiDyARVK1CIIYgD0IgiIR8IA4gDiAPQiCGfCIOVq18IA4gDiAUQv////8PgyIUIAp+IhEgAiALfnwiDyARVK0gDyAPIBMgDEL+////D4MiEX58Ig9WrXx8Ig5WrXwgDiAEIBR+IhggECARfnwiBCACIAp+fCIKIAsgE358IhBCIIggCiAQVq0gBCAYVK0gBCAKVq18fEIghoR8IgQgDlStfCAEIA8gAiARfiICIAsgFH58IgtCIIggAiALVq1CIIaEfCICIA9UrSACIBBCIIZ8IAJUrXx8IgIgBFStfCIEQv////////8AWARAIBYgF4QhFSAFQdAAaiACIAQgAyASEGAgAUIxhiAFKQNYfSAFKQNQIgFCAFKtfSEKQgAgAX0hCyAGQf7/AGoMAQsgBUHgAGogBEI/hiACQgGIhCICIARCAYgiBCADIBIQYCABQjCGIAUpA2h9IAUpA2AiDEIAUq19IQpCACAMfSELIAEhDCAGQf//AGoLIgZB//8BTgRAIA1CgICAgICAwP//AIQhDUIAIQEMAQsCfiAGQQBKBEAgCkIBhiALQj+IhCEKIARC////////P4MgBq1CMIaEIQwgC0IBhgwBCyAGQY9/TARAQgAhAQwCCyAFQUBrIAIgBEEBIAZrEK8BIAVBMGogDCAVIAZB8ABqEGYgBUEgaiADIBIgBSkDQCICIAUpA0giDBBgIAUpAzggBSkDKEIBhiAFKQMgIgFCP4iEfSAFKQMwIgQgAUIBhiIBVK19IQogBCABfQshBCAFQRBqIAMgEkIDQgAQYCAFIAMgEkIFQgAQYCAMIAIgAiADIAJCAYMiASAEfCIDVCAKIAEgA1atfCIBIBJWIAEgElEbrXwiAlatfCIEIAIgAiAEQoCAgICAgMD//wBUIAMgBSkDEFYgASAFKQMYIgRWIAEgBFEbca18IgJWrXwiBCACIARCgICAgICAwP//AFQgAyAFKQMAViABIAUpAwgiA1YgASADURtxrXwiASACVK18IA2EIQ0LIAAgATcDACAAIA03AwggBUHQAmokAAu/AgEBfyMAQdAAayIEJAACQCADQYCAAU4EQCAEQSBqIAEgAkIAQoCAgICAgID//wAQSyAEKQMoIQIgBCkDICEBIANB//8BSQRAIANB//8AayEDDAILIARBEGogASACQgBCgICAgICAgP//ABBLQf3/AiADIANB/f8CThtB/v8BayEDIAQpAxghAiAEKQMQIQEMAQsgA0GBgH9KDQAgBEFAayABIAJCAEKAgICAgICAORBLIAQpA0ghAiAEKQNAIQEgA0H0gH5LBEAgA0GN/wBqIQMMAQsgBEEwaiABIAJCAEKAgICAgICAORBLQeiBfSADIANB6IF9TBtBmv4BaiEDIAQpAzghAiAEKQMwIQELIAQgASACQgAgA0H//wBqrUIwhhBLIAAgBCkDCDcDCCAAIAQpAwA3AwAgBEHQAGokAAs1ACAAIAE3AwAgACACQv///////z+DIARCMIinQYCAAnEgAkIwiKdB//8BcXKtQjCGhDcDCAvAAQIBfwJ+QX8hAwJAIABCAFIgAUL///////////8AgyIEQoCAgICAgMD//wBWIARCgICAgICAwP//AFEbDQAgAkL///////////8AgyIFQoCAgICAgMD//wBWIAVCgICAgICAwP//AFJxDQAgACAEIAWEhFAEQEEADwsgASACg0IAWQRAIAEgAlIgASACU3ENASAAIAEgAoWEQgBSDwsgAEIAUiABIAJVIAEgAlEbDQAgACABIAKFhEIAUiEDCyADC0sBAn8gACgCACIBBEACfyABKAIMIgIgASgCEEYEQCABIAEoAgAoAiQRAAAMAQsgAigCAAtBf0cEQCAAKAIARQ8LIABBADYCAAtBAQtLAQJ/IAAoAgAiAQRAAn8gASgCDCICIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAItAAALQX9HBEAgACgCAEUPCyAAQQA2AgALQQELpAEBA38gAUEISwRAQQQgASABQQRNGyEBQQEgACAAQQFNGyEAA0ACQCAAIAFqQQFrQQAgAWtxIgIgACAAIAJJGyEDQQAhBCMAQRBrIgIkAAJAIAFBA3ENACADIAFwDQAgAkEMaiABIAMQgwQhA0EAIAIoAgwgAxshBAsgAkEQaiQAIAQiAg0AQayZNf4QAgAiA0UNACADEQkADAELCyACDwsgABAyCwkAIAFBARDyAwsTACABQQhLBEAgABAvDwsgABAvC4YBAQN/IwBBEGsiBCQAIwBBIGsiAyQAIANBGGogACABEL0CIANBEGogA0EMaiADKAIYIAMoAhwgAhC8AiADIAAgAygCECAAa2o2AgwgAyACIAMoAhQgAmtqNgIIIAQgAygCDDYCCCAEIAMoAgg2AgwgA0EgaiQAIAQoAgwhBSAEQRBqJAAgBQsJACAAEL4CEC8LpQEBB38jAEEQayICJAAgACgCQCIBBH8gAkHSATYCBCACQQhqIAEgAkEEahBRIQEgACAAKAIAKAIYEQAAIQQgASgCACEGIAFBADYCACAGEKwEIQUgAEEANgJAIABBAEEAIAAoAgAoAgwRAwAaIAEoAgAhAyABQQA2AgAgAwRAIAMgAUEEaigCABEAABoLQQAgACAEIAVyGwVBAAshByACQRBqJAAgBwsKACAAQaSKNRB5C4YC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KAIANgIADwsgAiACKAIAIgFBBGo2AgAgACABMgEANwMADwsgAiACKAIAIgFBBGo2AgAgACABMwEANwMADwsgAiACKAIAIgFBBGo2AgAgACABMAAANwMADwsgAiACKAIAIgFBBGo2AgAgACABMQAANwMADwsgAiACKAIAQQdqQXhxIgFBCGo2AgAgACABKwMAOQMADwsgACACIAMRAgALDwsgAiACKAIAIgFBBGo2AgAgACABNAIANwMADwsgAiACKAIAIgFBBGo2AgAgACABNQIANwMADwsgAiACKAIAQQdqQXhxIgFBCGo2AgAgACABKQMANwMAC3IBA38gACgCACwAAEEwa0EKTwRAQQAPCwNAIAAoAgAhA0F/IQEgAkHMmbPmAE0EQEF/IAMsAABBMGsiASACQQpsIgJqIAEgAkH/////B3NKGyEBCyAAIANBAWo2AgAgASECIAMsAAFBMGtBCkkNAAsgAguZEwIWfwF+IwBB0ABrIggkACAIIAE2AkwgCEE3aiEYIAhBOGohEgJAAkACQANAQQAhBwNAIAEhDSAHIBFB/////wdzSg0CIAcgEWohEQJAAkACQCABIgctAAAiCQRAA0ACQAJAIAlB/wFxIgFFBEAgByEBDAELIAFBJUcNASAHIQkDQCAJLQABQSVHBEAgCSEBDAILIAdBAWohByAJLQACIRogCUECaiIBIQkgGkElRg0ACwsgByANayIHIBFB/////wdzIhlKDQggAARAIAAgDSAHEGELIAcNBiAIIAE2AkwgAUEBaiEHQX8hDgJAIAEsAAFBMGsiC0EKTw0AIAEtAAJBJEcNACABQQNqIQcgCyEOQQEhEwsgCCAHNgJMQQAhDAJAIAcsAAAiCUEgayIBQR9LBEAgByELDAELIAchC0EBIAF0IgFBidEEcUUNAANAIAggB0EBaiILNgJMIAEgDHIhDCAHLAABIglBIGsiAUEgTw0BIAshB0EBIAF0IgFBidEEcQ0ACwsCQCAJQSpGBEAgC0EBaiEJAn8CQCALLAABQTBrQQpPDQAgCy0AAkEkRw0AIAksAABBMGshASALQQNqIQlBASETAn8gAEUEQCAEIAFBAnRqQQo2AgBBAAwBCyADIAFBA3RqKAIACwwBCyATDQYgAEUEQCAIIAk2AkxBACETQQAhDwwDCyACIAIoAgAiAUEEajYC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BQUAAQIDBAsgAUEQayIBKwMAIAArAwBkRQ0EIAIgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASACKAIINgIIIAEgAikDADcDAAwECyAAQRBqIQMgAUEQayIBKwMAIQkgACsDECIKIAArAwBkRQRAIAkgCmRFDQQgAiAD/QADAP0LAwAgAyABKAIINgIIIAMgASkDADcDACABIAIoAgg2AgggASACKQMANwMAIAArAxAgACsDAGRFDQQgAiAA/QADAP0LAwAgACADKAIINgIIIAAgAykDADcDACADIAIoAgg2AgggAyACKQMANwMADAQLIAkgCmQEQCACIAD9AAMA/QsDACAAIAEoAgg2AgggACABKQMANwMAIAEgAigCCDYCCCABIAIpAwA3AwAMBAsgAiAA/QADAP0LAwAgACADKAIINgIIIAAgAykDADcDACADIAIoAgg2AgggAyACKQMANwMAIAErAwAgACsDEGRFDQMgAiAD/QADAP0LAwAgAyABKAIINgIIIAMgASkDADcDACABIAIoAgg2AgggASACKQMANwMADAMLIAAgAEEQaiAAQSBqIAFBEGsQ2AEaDAILIAAgAEEQaiIEIABBIGoiAyAAQTBqIgUQ2AEaIAFBEGsiASsDACAAKwMwZEUNASACIAX9AAMA/QsDACAFIAEoAgg2AgggBSABKQMANwMAIAEgAigCCDYCCCABIAIpAwA3AwAgBSsDACADKwMAZEUNASACIAP9AAMA/QsDACADIAUoAgg2AgggAyAFKQMANwMAIAUgAigCCDYCCCAFIAIpAwA3AwAgAysDACAEKwMAZEUNASACIAT9AAMA/QsDACAEIAMoAgg2AgggBCADKQMANwMAIAMgAigCCDYCCCADIAIpAwA3AwAgACsDECAAKwMAZEUNASACIAD9AAMA/QsDACAAIAQoAgg2AgggACAEKQMANwMAIAQgAigCCDYCCCAEIAIpAwA3AwAMAQsgAEEQaiEEIABBIGohAyAAKwMgIQkCQCAAKwMQIgogACsDACILZEUEQCAJIApkRQ0BIAIgBP0AAwD9CwMAIAQgA0EIaigCADYCCCAEIAMpAwA3AwAgAyACKAIINgIIIAMgAikDADcDACAEKwMAIAtkRQ0BIAIgAP0AAwD9CwMAIAAgBCgCCDYCCCAAIAQpAwA3AwAg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IABBhBlqIABBlBJqKAIANgIAIABB/BhqIAApAowSNwIAIABBADoA/hEgAEHpyAE7AfwRIABBAjoAhxIgAEH4EWoiAkHaGC8AADsBACAAQYAUOwH6ESAAQRA2AuwRIABB0hgpAAAiEzcC8BEgAEGQGWogAEGEEmooAgA2AgAgACAAKQL8ETcDiBkgAEGUGWpBEDYCACAAQaAZaiACKAIANgIAIABBmBlqIBM3AwAgAEEAOgDiESAAQejSATsB4BEgAEECOgDrESAAQdgRakHtGy0AADoAACAAQQU6AN8RIABBETYC0BEgAEEAOgDZESAAQekbKAAANgLUESAAQawZaiAAQegRaigCADYCACAAIAApAuARNwKkGSAAQbAZakERNgIAIABBvBlqIABB3BFqKAIANgIAIABBtBlqIAApAtQRNwIAIABBADoAxhEgAEHm0gE7AcQRIABBAjoAzxEgAEG7EWpBlRwoAAA2AAAgAEEHOgDDESAAQRI2ArQRIABBADoAvxEgAEGSHCgAADYCuBEgAEHIGWogAEHMEWooAgA2AgAgACAAKQLEETcDwBkgAEHMGWpBEjYCACAAQdgZaiAAQcARaigCADYCACAAQdAZaiAAKQK4ETcDACAAQQA6AKoRIABB9tIBOwGoESAAQQI6ALMRIABBpBFqIgJB4CEvAAA7AQAgAEGAFDsBphEgAEETNgKYESAAQdghKQAAIhM3ApwRIABB5BlqIABBsBFqKAIANgIAIAAgACkCqBE3AtwZIABB6BlqQRM2AgAgAEH0GWogAigCADYCACAAQewZaiATNwIAIABBADoAjhEgAEHoygE7AYwRIABBAjoAlxEgAEGEEWpBtwovAAA7AQAgAEEGOgCLESAAQRQ2AvwQIABBADoAhhEgAEGzCigAADYCgBEgAEGAGmogAEGUEWooAgA2AgAgACAAKQKMETcD+BkgAEGEGmpBFDYCACAAQZAaaiAAQYgRaigCADYCACAAQYgaaiAAKQKAETcDACAAQQA6APIQIABB9dYBOwHwECAAQQI6APsQIABB7BBqIgJBjBktAAA6AAAgAEEJOgDvECAAQRU2AuAQIABBADoA7RAgAEGEGSkAACITNwLkECAAQZwaaiAAQfgQaigCADYCACAAIAApAvAQNwKUGiAAQaAaakEVNgIAIABBrBpqIAIoAgA2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IABB4B9qQY4ZKQAAIhM3AwAgAEHYH2ogAEHMC2ooAgA2AgAgAEEJOgDDCyAAQQA6AMELIABB6B9qIAIoAgA2AgAgAEEuNgK0CyAAIBM3ArgLIAAgACkCxAs3A9AfIABBADoAqgsgAEHr3AE7AagLIABBAjoAswsgAEGfC2pBmCkoAAA2AAAgAEEHOgCnCyAAQS82ApgLIABBADoAowsgAEGVKSgAADYCnAsgAEH0H2ogAEGwC2ooAgA2AgAgACAAKQKoCzcC7B8gAEH4H2pBLzYCACAAQYQgaiAAQaQLaigCADYCACAAQfwfaiAAKQKcCzcCACAAQQA6AI4LIABB5egBOwGMCyAAQQI6AJcLIABBiAtqIgJBADoAACAAQQg6AIsLIABBMDYC/AogAELl5tH75q3asO4ANwKACyAAQZAgaiAAQZQLaigCADYCACAAIAApAowLNwOIICAAQZQgakEwNgIAIABBoCBqIAIoAgA2AgAgAEGYIGpC5ebR++at2rDuADcDACAAQQA6APIKIABB7dYBOwHwCiAAQQI6APsKIABB7ApqIgJBgRkvAAA7AQAgAEEKOgDvCiAAQTE2AuAKIABBADoA7gogAEH5GCkAACITNwLkCiAAQawgaiAAQfgKaigCADYCACAAIAApAvAKNwKkICAAQbAgakExNgIAIABBvCBqIAIoAgA2AgAgAEG0IGogEzcCACAAQQA6ANYKIABB4uQBOwHUCiAAQQI6AN8KIABBzApqQbkWLwAAOwEAIABBBjoA0wogAEEyNgLECiAAQQA6AM4KIABBtRYoAAA2AsgKIABByCBqIABB3ApqKAIANgIAIAAgACkC1Ao3A8AgIABBzCBqQTI2AgAgAEHYIGogAEHQCmooAgA2AgAgAEHQIGogACkCyAo3AwAgAEEAOgC6CiAAQeXqATsBuAogAEECOgDDCiAAQbAKakGhHy8AADsBACAAQQY6ALcKIABBMzYCqAogAEEAOgCyCiAAQZ0fKAAANgKsCiAAQeQgaiAAQcAKaigCADYCACAAIAApArgKNwLcICAAQeggakEzNgIAIABB9CBqIABBtApqKAIANgIAIABB7CBqIAApAqwKNwIAIABBADoAngogAEHp5gE7AZwKIABBAjoApwogAEGYCmoiAkHXJi0AADoAACAAQQk6AJsKIABBNDYCjAogAEEAOgCZCiAAQc8mKQAAIhM3ApAKIABBgCFqIABBpApqKAIANgIAIAAgACkCnAo3A/ggIABBhCFqQTQ2AgAgAEGQIWogAigCADYCACAAQYghaiATNwMAIABBADoAggogAEHo8gE7AYAKIABBAjoAiwogAEH8CWoiAkEAOgAAIABBCDoA/wkgAEE1NgLwCSAAQuHktavmrdqw7gA3AvQJIABBnCFqIABBiApqKAIANgIAIAAgACkCgAo3ApQhIABBoCFqQTU2AgAgAEGsIWogAigCADYCACAAQaQhakLh5LWr5q3asO4ANwIAIABBADoA5gkgAEHuygE7AeQJIABBAjoA7wkgAEHcCWpByBsvAAA7AQAgAEEGOgDjCSAAQTY2AtQJIABBADoA3gkgAEHEGygAADYC2AkgAEG4IWogAEHsCWooAgA2AgAgACAAKQLkCTcDsCEgAEG8IWpBNjYCACAAQcghaiAAQeAJaigCADYCACAAQcAhaiAAKQLYCTcDACAAQQA6AMoJIABB7dwBOwHICSAAQQI6ANMJIABBxAlqIgJBqxktAAA6AAAgAEEJOgDHCSAAQTc2ArgJIABBADoAxQkgAEGjGSkAACITNwK8CSAAQdQhaiAAQdAJaigCADYCACAAIAApAsgJNwLMISAAQdghakE3NgIAIABB5CFqIAIoAgA2AgAgAEHcIWogEzcCACAAQQA6AK4JIABB4uYBOwGsCSAAQQI6ALcJIABBowlqQfQYKAAANgAAIABBBzoAqwkgAEE4NgKcCSAAQQA6AKcJIABB8RgoAAA2AqAJIABB8CFqIABBtAlqKAIANgIAIAAgACkCrAk3A+ghIABB9CFqQTg2AgAgAEGAImogAEGoCWooAgA2AgAgAEH4IWogACkCoAk3AwAgAEEAOgCSCSAAQevWATsBkAkgAEECOgCbCSAAQYgJakHyHC8AADsBACAAQQY6AI8JIABBOTYCgAkgAEEAOgCKCSAAQe4cKAAANgKECSAAQYwiaiAAQZgJaigCADYCACAAIAApApAJNwKEIiAAQZAiakE5NgIAIABBnCJqIABBjAlqKAIANgIAIABBlCJqIAApAoQJNwIAIABBADoA9gggAEHz4gE7AfQIIABBAjoA/wggAEHwCGoiAkEAOgAAIABBCDoA8wggAEE6NgLkCCAAQuHYiYvmrdqw7gA3AugIIABBqCJqIABB/AhqKAIANgIAIAAgACkC9Ag3A6AiIABBrCJqQTo2AgAgAEG4ImogAigCADYCACAAQbAiakLh2ImL5q3asO4ANwMAIABBADoA2gggAEHz7gE7AdgIIABBAjoA4wggAEHPCGpBvxsoAAA2AAAgAEEHOgDXCCAAQTs2AsgIIABBADoA0wggAEG8GygAADYCzAggAEHEImogAEHgCGooAgA2AgAgACAAKQLYCDcCvCIgAEHIImpBOzYCACAAQdQiaiAAQdQIaigCADYCACAAQcwiaiAAKQLMCDcCACAAQQA6AL4IIABB59gBOwG8CCAAQQI6AMcIIABBuAhqIgJBADoAACAAQQg6ALsIIABBPDYCrAggAELnwrHLtqzasO4ANwKwCCAAQeAiaiAAQcQIaigCADYCACAAIAApArwINwPYIiAAQeQiakE8NgIAIABB8CJqIAIoAgA2AgAgAEHoImpC58Kxy7as2rDuADcDACAAQQA6AKIIIABB7eQBOwGgCCAAQQI6AKsIIABBlwhqQd0bKAAANgAAIABBBzoAnwggAEE9NgKQCCAAQQA6AJsIIABB2hsoAAA2ApQIIABB/CJqIABBqAhqKAIANgIAIAAgACkCoAg3AvQiIABBgCNqQT02AgAgAEGMI2ogAEGcCGooAgA2AgAgAEGEI2ogACkClAg3AgAgAEEAOgCGCCAAQfDCATsBhAggAEECOgCPCCAAQfIbKAAANgD7ByAAQQc6AIMIIABBPjYC9AcgAEEAOgD/ByAAQe8bKAAANgL4ByAAQZgjaiAAQYwIaigCADYCACAAIAApAoQINwOQIyAAQZwjakE+NgIAIABBqCNqIABBgAhqKAIANgIAIABBoCNqIAApAvgHNwMAIABBADoA6gcgAEHz0gE7AegHIABBAjoA8wcgAEGCKSgAADYA3wcgAEEHOgDnByAAQT82AtgHIABBADoA4wcgAEH/KCgAADYC3AcgAEG0I2ogACgC8Ac2AgAgACAAKQLoBzcCrCMgAEG4I2pBPzYCACAAQcQjaiAAKALkBzYCACAAQbwjaiAAKQLcBzcCACAAQQA6AM4HIABB69oBOwHMByAAQQI6ANcHIABBxxQtAAA6AMQHIABBBToAywcgAEHAADYCvAcgAEEAOgDFByAAQcMUKAAANgLAByAAQdAjaiAAKALUBzYCACAAIAApAswHNwPIIyAAQdQjakHAADYCACAAQeAjaiAAKALIBzYCACAAQdgjaiAAKQLABzcDACAAQQA6ALIHIABB89wBOwGwByAAQQI6ALsHIABB9ygtAAA6AKgHIABBBToArwcgAEHBADYCoAcgAEEAOgCpByAAQfMoKAAANgKkByAAQewjaiAAKAK4BzYCACAAIAApArAHNwLkIyAAQfAjakHBADYCACAAQfwjaiAAKAKsBzYCACAAQfQjaiAAKQKkBzcCACAAQQA6AJYHIABB+d4BOwGUByAAQQI6AJ8HIABBoSkvAAA7AYwHIABBBjoAkwcgAEHCADYChAcgAEEAOgCOByAAQZ0pKAAANgKIByAAQYgkaiAAKAKcBzYCACAAIAApApQHNwOAJCAAQYwkakHCADYCACAAQZgkaiAAKAKQBzYCACAAQZAkaiAAKQKIBzcDACAAQQA6APoGIABB894BOwH4BiAAQQI6AIMHIABBzxsvAAA7AfAGIABBBjoA9wYgAEHDADYC6AYgAEEAOgDyBiAAQcsbKAAANgLsBiAAQaQkaiAAKAKABzYCACAAIAApAvgGNwKcJCAAQagkakHDADYCACAAQbQkaiAAKAL0BjYCACAAQawkaiAAKQLsBjcCACAAQQA6AN4GIABB4cwBOwHcBiAAQQI6AOcGIABBwxAtAAA6ANgGIABBCToA2wYgAEHEADYCzAYgAEEAOgDZBiAAQbsQKQAAIhM3AtAGIABBwCRqIAAoAuQGNgIAIAAgACkC3AY3A7gkIABBxCRqQcQANgIAIABB0CRqIAAoAtgGNgIAIABByCRqIBM3AwAgAEEAOgDCBiAAQe/GATsBwAYgAEECOgDLBiAAQYkYKAAANgC3BiAAQQc6AL8GIABBxQA2ArAGIABBADoAuwYgAEGGGCgAADYCtAYgAEHcJGogACgCyAY2AgAgACAAKQLABjcC1CQgAEHgJGpBxQA2AgAgAEHsJGogACgCvAY2AgAgAEHkJGogACkCtAY3AgAgAEEAOgCmBiAAQevCATsBpAYgAEECOgCvBiAAQQA6AKAGIABBCDoAowYgAEHGADYClAYgAELnyr2T96zasO4ANwKYBiAAQfgkaiAAKAKsBjYCACAAIAApAqQGNwPwJCAAQfwkakHGADYCACAAQYglaiAAKAKgBjYCACAAQYAlakLnyr2T96zasO4ANwMAIABBADoAigYgAEHiygE7AYgGIABBAjoAkwYgAEG/GC8AADsBhAYgAEEKOgCHBiAAQccANgL4BSAAQQA6AIYGIABBtxgpAAAiEzcC/AUgAEGUJWogACgCkAY2AgAgACAAKQKIBjcCjCUgAEGYJWpBxwA2AgAgAEGkJWogACgChAY2AgAgAEGcJWogEzcCACAAQQA6AO4FIABB9M4BOwHsBSAAQQI6APcFIABBjxstAAA6AOQFIABBBToA6wUgAEHIADYC3AUgAEEAOgDlBSAAQYsbKAAANgLgBSAAQbAlaiAAKAL0BTYCACAAIAApAuwFNwOoJSAAQbQlakHIADYCACAAQcAlaiAAKALoBTYCACAAQbglaiAAKQLgBTcDACAAQQA6ANIFIABB88gBOwHQBSAAQQI6ANsFIABB5hsvAAA7AcgFIABBBjoAzwUgAEHJADYCwAUgAEEAOgDKBSAAQeIbKAAANgLEBSAAQcwlaiAAKALYBTYCACAAIAApAtAFNwLEJSAAQdAlakHJADYCACAAQdwlaiAAKALMBTYCACAAQdQlaiAAKQLEBTcCACAAQQA6ALYFIABB5+oBOwG0BSAAQQI6AL8FIABBADoAsAUgAEEIOgCzBSAAQcoANgKkBSAAQufqqYumrpi66QA3AqgFIABB6CVqIAAoArwFNgIAIAAgACkCtAU3A+AlIABB7CVqQcoANgIAIABB+CVqIAAoArAFNgIAIABB8CVqQufqqYumrpi66QA3AwAgAEEAOgCaBSAAQeHaATsBmAUgAEECOgCjBSAAQcomKAAANgCPBSAAQQc6AJcFIABBywA2AogFIABBADoAkwUgAEHHJigAADYCjAUgAEGEJmogACgCoAU2AgAgACAAKQKYBTcC/CUgAEGIJmpBywA2AgAgAEGUJmogACgClAU2AgAgAEGMJmogACkCjAU3AgAgAEEAOgD+BCAAQfnSATsB/AQgAEECOgCHBSAAQdkcKAAANgDzBCAAQQc6APsEIABBzAA2AuwEIABBADoA9wQgAEHWHCgAADYC8AQgAEGgJmogACgChAU2AgAgACAAKQL8BDcDmCYgAEGkJmpBzAA2AgAgAEGwJmogACgC+AQ2AgAgAEGoJmogACkC8AQ3AwAgAEEAOgDiBCAAQezeATsB4AQgAEECOgDrBCAAQZMWLQAAOgDWBCAAQQM6AN8EIABBzQA2AtAEIABBADoA1wQgAEGRFi8AADsB1AQgAEG8JmogACgC6AQ2AgAgACAAKQLgBDcCtCYgAEHAJmpBzQA2AgAgAEHMJmogACgC3AQ2AgAgAEHEJmogACkC1AQ3AgAgAEEAOgDGBCAAQfX0ATsBxAQgAEECOgDPBCAAQZsbLQAAOgC8BCAAQQU6AMMEIABBzgA2ArQEIABBADoAvQQgAEGXGygAADYCuAQgAEHYJmogACgCzAQ2AgAgACAAKQLEBDcD0CYgAEHcJmpBzgA2AgAgAEHoJmogACgCwAQ2AgAgAEHgJmogACkCuAQ3AwAgAEEAOgCqBCAAQebeATsBqAQgAEECOgCzBCAAQbchKAAANgCfBCAAQQc6AKcEIABBzwA2ApgEIABBADoAowQgAEG0ISgAADYCnAQgAEH0JmogACgCsAQ2AgAgACAAKQKoBDcC7CYgAEH4JmpBzwA2AgAgAEGEJ2ogACgCpAQ2AgAgAEH8JmogACkCnAQ3AgAgAEEAOgCOBCAAQejoATsBjAQgAEECOgCXBEEQEDIiDEEAOgAOIAxBjCMpAAA3AAYgDEGGIykAADcAACAAQZQnakHQADYCACAAQZAnaiAAKAKUBDYCACAAIAApAowENwOIJyAAQZgnaiAMQQ4QayAAQQA6AIIEIABB8OYBOwGABCAAQQI6AIsEIABBiRYvAAA7AfgDIABBsCdqQdEANgIAIABBrCdqIAAoAogENgIAIABBhRYoAAA2AvQDIABBADoA+gMgAEG0J2ogACkC9AM3AgAgAEEGOgD/AyAAQbwnaiAAKAL8AzYCACAAQdEANgLwAyAAIAApAoAENwKkJyAAQQA6AOYDIABB9NYBOwHkAyAAQQI6AO8DIABB+hcoAAA2ANsDIABBBzoA4wMgAEHSADYC1AMgAEEAOgDfAyAAQfcXKAAANgLYAyAAQcgnaiAAKALsAzYCACAAIAApAuQDNwPAJyAAQcwnakHSADYCACAAQdgnaiAAKALgAzYCACAAQdAnaiAAKQLYAzcDACAAQQA6AMoDIABB7twBOwHIAyAAQQI6ANMDIABByRooAAA2AL8DIABBBzoAxwMgAEHTADYCuAMgAEEAOgDDAyAAQcYaKAAANgK8AyAAQeQnaiAAKALQAzYCACAAIAApAsgDNwLcJyAAQegnakHTADYCACAAQfQnaiAAKALEAzYCACAAQewnaiAAKQK8AzcCACAAQQA6AK4DIABB7egBOwGsAyAAQQI6ALcDIABBryEoAAA2AKMDIABBBzoAqwMgAEHUADYCnAMgAEEAOgCnAyAAQawhKAAANgKgAyAAQYAoaiAAKAK0AzYCACAAIAApAqwDNwP4JyAAQYQoakHUADYCACAAQZAoaiAAKAKoAzYCACAAQYgoaiAAKQKgAzcDACAAQQA6AJIDIABB88IBOwGQAyAAQQI6AJsDIABBADoAjAMgAEEIOgCPAyAAQdUANgKAAyAAQvPCuZu3zdy09AA3AoQDIABBnChqIAAoApgDNgIAIAAgACkCkAM3ApQoIABBoChqQdUANgIAIABBrChqIAAoAowDNgIAIABBpChqQvPCuZu3zdy09AA3AgAgAEEAOgD2AiAAQezEATsB9AIgAEECOgD/AkEQEDIiDUEAOgANIA1BxRwpAAA3AAUgDUHAHCkAADcAACAAQbwoakHWADYCACAAQbgoaiAAKAL8AjYCACAAIAApAvQCNwOwKCAAQcAoaiANQQ0QayAAQQA6AOoCIABB7fIBOwHoAiAAQQI6APMCIABB/RQoAAA2AN8CIABB2ChqQdcANgIAIABB1ChqIAAoAvACNgIAIABB+hQoAAA2AtwCIABBADoA4wIgAEHcKGogACkC3AI3AgAgAEEHOgDnAiAAQeQoaiAAKALkAjYCACAAQdcANgLYAiAAIAApAugCNwLMKCAAQQA6AM4CIABB4t4BOwHMAiAAQQI6ANcCIABBkRgoAAA2AMMCIABBBzoAywIgAEHYADYCvAIgAEEAOgDHAiAAQY4YKAAANgLAAiAAQfAoaiAAKALUAjYCACAAIAApAswCNwPoKCAAQfQoakHYADYCACAAQYApaiAAKALIAjYCACAAQfgoaiAAKQLAAjcDACAAQQA6ALICIABB9NgBOwGwAiAAQQI6ALsCIABBlR0oAAA2AKcCIABBBzoArwIgAEHZADYCoAIgAEEAOgCrAiAAQZIdKAAANgKkAiAAQYwpaiAAKAK4AjYCACAAIAApArACNwKEKSAAQZApakHZADYCACAAQZwpaiAAKAKsAjYCACAAQZQpaiAAKQKkAjcCACAAQQA6AJYCIABB7c4BOwGUAiAAQQI6AJ8CIABBADoAkAIgAEEIOgCTAiAAQdoANgKEAiAAQu3CsYv2rNi5+QA3AogCIABBqClqIAAoApwCNgIAIAAgACkClAI3A6ApIABBrClqQdoANgIAIABBuClqIAAoApACNgIAIABBsClqQu3CsYv2rNi5+QA3AwAgAEEAOgD6ASAAQeHmATsB+AEgAEECOgCDAiAAQQA6APQBIABBCDoA9wEgAEHbADYC6AEgAELh5s2L1q3ZueUANwLsASAAQcQpaiAAKAKAAjYCACAAIAApAvgBNwK8KSAAQcgpakHbADYCACAAQdQpaiAAKAL0ATYCACAAQcwpakLh5s2L1q3ZueUANwIAIABBADoA3gEgAEH06AE7AdwBIABBAjoA5wEgAEH4FC0AADoA1AEgAEEFOgDbASAAQdwANgLMASAAQQA6ANUBIABB9BQoAAA2AtABIABB4ClqIAAoAuQBNgIAIAAgACkC3AE3A9gpIABB5ClqQdwANgIAIABB8ClqIAAoAtgBNgIAIABB6ClqIAApAtABNwMAIABBAzoAywEgAEEAOgDDASAAQbwKLQAAOgDCASAAQboKLwAAOwHAASAAQQA6ALwBIABBCDoAvwEgAEHdADYCsAEgAELowt2Llq3asO4ANwK0ASAAQfwpaiAAKALIATYCACAAIAApAsABNwL0KSAAQYAqakHdADYCACAAQYwqaiAAKAK8ATYCACAAQYQqakLowt2Llq3asO4ANwIAIABBADoApgEgAEHs3AE7AaQBIABBAjoArwEgAEGKKSgAADYAmwEgAEEHOgCjASAAQd4ANgKUASAAQQA6AJ8BIABBhykoAAA2ApgBIABBmCpqIAAoAqwBNgIAIAAgACkCpAE3A5AqIABBnCpqQd4ANgIAIABBqCpqIAAoAqABNgIAIABBoCpqIAApApgBNwMAIABBADoAigEgAEHowgE7AYgBIABBAjoAkwEgAEHxKC0AADoAgAEgAEEFOgCHASAAQd8ANgJ4IABBADoAgQEgAEHtKCgAADYCfCAAQbQqaiAAKAKQATYCACAAIAApAogBNwKsKiAAQbgqakHfADYCACAAQcQqaiAAKAKEATYCACAAQbwqaiAAKQJ8NwIAIABBADoAbiAAQeLCATsBbCAAQQI6AHcgAEGyFCgAADYAYyAAQQc6AGsgAEHg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IAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQdjhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGZ4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB1OEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQavhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUHB4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFByeEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEBEDkgACABQbThABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGF4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB6OEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQefhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUH+4AAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB3+EAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQaHhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGN4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3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QTBqIQEgAkEwaiICIA1HDQALCyADIAE2AgQMAgsgASACIBH8CgAAIAMgASAMQTBsajYCBAwBCyABBEAgAyABNgIEIAEQLyADQQA2AgggA0IANwIAQQAhBwsgDEHWqtUqTw0CQdWq1SogB0EwbSIBQQF0IgcgDCAHIAxLGyABQarVqhVPGyIBQdaq1SpPDQIgAyABQTBsIgcQMiIBNgIEIAMgATYCACADIAEgB2o2AgggAyACIA1HBH8gASACIBFBMGsiAiACQTBwa0EwaiIC/AoAACABIAJqBSABCzYCBAsgAyAEKAJENgI0IAMgBCkCPDcCLCADIAT9AAIs/QsCHCADIAT9AAIc/QsCDCAIQYgCaiIBIARByABqRwRAIAEgBCgCSCAEKAJMENQEIAhBlAJqIAQoAlQgBCgCWBDTBAsgCCAEKQJgNwKgAiAEKAIAIRQgBSgCnBoiCEEANgJMIAgoAlAiEUUNACAGQQhqIQ1BACEMA0AgCCgCWCAMQQR0aiIEQQhqIgMhAiADKAIAIgchAQJAIAdFDQADQCACIAEgASgCECAUSCIPGyECIAFBBGogASAPGygCACIBDQALIAIgA0YNACACKAIQIBRKDQAgBCgCAEH+////B0sNAAJ/A0AgDSAHIgEoAhAiAkgEQCABKAIAIgcNASABDAILIAIgDU4NAiABKAIEIgcNAAsgAUEEagshAkEUEDIiAyABNgIIIANCADcCACADIA02AhAgAiADNgIAIAQoAgQoAgAiAQRAIAQgATYCBCACKAIAIQMLIAMgAyAEKAIIIhFGIgE6AAwCQCABDQADQCADKAIIIgItAAwNAQJAIAIgAigCCCIBKAIAIgdGBEACQCABKAIEIgdFDQAgBy0ADA0ADAILAkAgAyACKAIARgRAIAIhAwwBCyACIAIoAgQiAygCACIHNgIEIAMgBwR/IAcgAjYCCCACKAIIBSABCzYCCCACKAIIIgEgASgCACACR0ECdGogAzYCACADIAI2AgAgAiADNgIIIAMoAggiASgCACECCyADQQE6AAwgAUEAOgAMIAEgAigCBCIDNgIAIAMEQCADIAE2AggLIAIgASgCCDYCCCABKAIIIgMgAygCACABR0ECdGogAjYCACACIAE2AgQgASACNgIIDAMLAkAgB0UNACAHLQAMDQAMAQsCQCADIAIoAgBHBEAgAiEDDAELIAIgAygCBCIHNgIAIAMgBwR/IAcgAjYCCCACKAIIBSABCzYCCCACKAIIIgEgASgCACACR0ECdGogAzYCACADIAI2AgQgAiADNgIIIAMoAgghAQsgA0EBOgAMIAFBADoADCABIAEoAgQiAigCACIDNgIEIAMEQCADIAE2AggLIAIgASgCCDYCCCABKAIIIgMgAygCACABR0ECdGogAjYCACACIAE2AgAgASACNgIIDAILIAJBAToADCABIAEgEUY6AAwgB0EBOgAMIBEgASIDRw0ACwsgBCAEKAIMQQFqNgIMIAgoAlAhEQsgDEEBaiIMIBFJDQALCyAGQQFqIgYgBSgCnAYiAUgNAQwCCwsMGAtBACEIIAFBAEwNBgNAAkAgBSgCnBoiAiAIQdgUbGoiAy0AsQINACADLQCwAg0AIAJBzABqIAhBfxDvAiAFKAKcGiIGQQA2AkwgCEEIaiEJIAYoAlAiDgR/QQAhDANAIAYoAlggDEEEdGoiBEEIaiIDIQIgAygCACIHIQECQCAHRQ0AA0AgAiABIAEoAhAgCUgiDRshAiABQQRqIAEgDRsoAgAiAQ0ACyACIANGDQAgAigCECAJSg0AIAQoAgBB/v///wdLDQACfwNAIAggByIBKAIQIgJIBEAgASgCACIHDQEgAQwCCyACIAhODQIgASgCBCIHDQALIAFBBGoLIQJBFBAyIgMgATYCCCADQgA3AgAgAyAINgIQIAIgAzYCACAEKAIEKAIAIgEEQCAEIAE2AgQgAigCACEDCyADIAMgBCgCCCIORiIBOgAMAkAgAQ0AA0AgAygCCCICLQAMDQECQCACIAIoAggiASgCACIHRgRAAkAgASgCBCIHRQ0AIActAAwNAAwCCwJAIAMgAigCAEYEQCACIQMMAQsgAiACKAIEIgMoAgAiBzYCBCADIAcEfyAHIAI2AgggAigCCAUgAQs2AgggAigCCCIBIAEoAgAgAkdBAnRqIAM2AgAgAyACNgIAIAIgAzYCCCADKAIIIgEoAgAhAgsgA0EBOgAMIAFBADoADCABIAIoAgQiAzYCACADBEAgAyABNgIICyACIAEoAgg2AgggASgCCCIDIAMoAgAgAUdBAnRqIAI2AgAgAiABNgIEIAEgAjYCCAwDCwJAIAdFDQAgBy0ADA0ADAELAkAgAyACKAIARwRAIAIhAwwBCyACIAMoAgQiBzYCACADIAcEfyAHIAI2AgggAigCCAUgAQs2AgggAigCCCIBIAEoAgAgAkdBAnRqIAM2AgAgAyACNgIEIAIgAzYCCCADKAIIIQELIANBAToADCABQQA6AAwgASABKAIEIgIoAgAiAzYCBCADBEAgAyABNgIICyACIAEoAgg2AgggASgCCCIDIAMoAgAgAUdBAnRqIAI2AgAgAiABNgIAIAEgAjYCCAwCCyACQQE6AAwgASABIA5GOgAMIAdBAToADCAOIAEiA0cNAAsLIAQgBCgCDEEBajYCDCAGKAJQIQ4LIAxBAWoiDCAOSQ0ACyAFKAKcGgUgBgtBzABqIAlBfxDvAiAFKAKcBiEBCyAIQQFqIgggAUgNAAsLIAFBAEwNBSAVQQFqIQ5BACERA0ACQCAFKAKcGiARQdgUbGoiD0GxAmoiFC0AAA0AIA9BsAJqIgYtAAANAAJAIA8oAtQBQTBrIh0oAgAiBCAFKAKgGiIDKAL8ASIBSgRAIAQgAWtBAXQhAQJAIA8tALICRQ0AIA8oAqwCIAFMDQAgDygC3AEgFUgNAgsgDyABNgKsAiAPIA42AtwBIA9BAToAsgIgHSgCACEECwJAIA9BiAJqIiMoAgAgDygCjAJGDQAgDygClAIgDygCmAJGDQAgA0HUAWoiByEBAkACQCADKALUASICRQ0AA0AgBCACIgEoAhAiB0gEQCABIQcgASgCACICDQEMAgsgBCAHTA0CIAEoAgQiAg0ACyABQQRqIQcLQSAQMiICIAQ2AhAgAiABNgIIIAJCADcCACACQgA3AhQgAkEANgIcIAcgAjYCACACIQEgAygC0AEoAgAiBARAIAMgBDYC0AEgBygCACEBCyADKALUASABEKQBIAMgAygC2AFBAWo2AtgBCyACQRRqIgEoAgAgASACLQAfIgTAQQBIIgcbIgMhASADQQIgAigCGCAEIAcbIgIgAkECTxsiB2oiBCEIIAMhAiAHBEADQAJAIAFBAWohAiABLQAAQdsARgRAIAIgBEYNASABIAggAS0AAUHfAEYbIQggAiEBDAILIAIiASAERw0BCwsgCCECCyACIANGIAIgBEdxDQAgBSAPKQKgAiJMNwPwAyAFIEw3A7AaIAVByAZqIAMgBUHwA2oQ2AQCQCAFKALIBiIHIAUoAswGQQRrIiBGDQAgDygCmAIhDCAPKAKUAiEIIAchDQJAA0ACQCANKAIAIRcgBUEANgKsGiAFQgA3AqQaIAggDEcEQANAAkAgCCgCACIJIAgoAgQiAUYNAEEAIQMgAUEEayIEKAIAIgEoAgAiJUEDa0ECTwRAIAVB2Cs2AugDIAVB/x42AuQDIAVBphU2AuADQQJBsOQAIAVB4ANqEDQQAAALA0ACfyABKAIIIgJBBUYEQAJ/QQEgA0EBcQ0AGkEAIAEoAgQgF0sNABogASgCDCAXTwshAyABKAIQIQIgAUEQagwBCyABQQhqIRkgA0EBcQRAQQEhAyAZDAELIAEoAgQgF0YhAyAZCyEBIAJBBkYNAAsgJUEDRiADcw0AIAVBADYCuBogBUIANwKwGgJAAkAgBCAJRwRAIAQgCWsiAkEASA0GIAUgAhAyIgM2ArQaIAUgAzYCsBogBSADIAJBfHEiAmoiBDYCuBogAyAJIAL8CgAAIAUgAiADaiICNgK0GiABKAIAQQJJDQIgAiAERg0BIAIgATYCACAFIAJBBGo2ArQaDAILQQAhA0EAIQQgAkECSQ0BCyAEIANrIgJBAnUiJEEBaiIJQYCAgIAETw0GQf////8DIAJBAXUiGSAJIAkgGUkbIAJB/P///wdPGyIZBH8gGUGAgICABE8NHSAZQQJ0EDIFQQALIiUgJEECdGoiCSABNgIAIAlBBGohJCADIARHBEAgJSACIAJBBGtBfHEiAWtqQQRrIgkgBCABa0EEayABQQRq/AoAAAsgBSAlIBlBAnRqNgK4GiAFICQ2ArQaIAUgCTYCsBogA0UNACADEC8LICMgBUGwGmogBUGkGmoQiwIgBSgCsBoiAUUNACAFIAE2ArQaIAEQLwsgCEEMaiIIIAxHDQALIA8oApQCIQwLIAwEQCAPKAKYAiICIAwiAUcEQANAIAJBDGsiASgCACIDBEAgAkEIayADNgIAIAMQLwsgASICIAxHDQALIA8oApQCIQELIA8gDDYCmAIgARAvCyAPIAUoAqQaIgg2ApQCIA8gBSgCqBoiDDYCmAIgDyAFKAKsGjYCnAIgDUEEaiINICBHDQEMAwsLDBwLDBsLIA8gBSkC1AY3AqACIAdFDQAgBxAvCwJAAkACQAJAIB0oAgAgBSgCoBoiASgC3AFGDQAgECgCMCICQQBKIAIgFUxxDQAgDy0AsgJFDQEgLSAPKAKsAmogIUgNAQsgDygC3AFFBEAgLSAPKAKsAmogIUgNBCAPIA42AtwBCyAQLQAXRQ0CIA8gDjYC3AEMAQsgASgCsAFFDQAgFSAuRw0DIA8oAtwBRQ0CIA8oAqwCQdwLTg0DDAILIA9BuBc2AqwCCyAUIQYLIAZBAToAAAsgEUEBaiIRIAUoApwGIgJIDQALIAJBAEwNBkEBIQQgAkEBcSEGQQAhASAFKAKcGiEDIAJBAUcEQCACQX5xIQdBACECA0AgAyABQdgUbGoiCC0AsQJFBEAgCC0AsAJBAEcgBHEhBAsgAyABQQFyQdgUbGoiCC0AsQJFBEAgCC0AsAJBAEcgBHEhBAsgAUECaiEBIAJBAmoiAiAHRw0ACwsCQCAGRQ0AIAMgAUHYFGxqIgEtALECDQAgAS0AsAJBAEcgBHEhBAsgBEEBcQ0FEGkhTCAFKAKcGiICQQA2ArQBIAIgAikDACBMIE19fDcDACAFKAKcBiIEQQBKBEAgBSgCtAYgBSgCsAZrQQJ1IBVqIQZBACEHQQAhAQNAAkAgBSgCnBogAUHYFGxqIgMtALACDQAgAy0AsQINACADIAc2AqgCIAIoArgBIAdBAnRqIAMoAtQBQTBrKAIANgIAIAIoArwBIAIoArQBQQJ0aiAGNgIAIAIoAsABIAIoArQBQQJ0akEBNgIAIAIoAsQBIAIoArQBQQJ0aigCACABNgIAIAIoAsgBIAIoArQBakEBOgAAIAIgAigCtAFBAWoiBzYCtAEgBSgCnAYhBAsgAUEBaiIBIARIDQALIAUoApwaIQILIAUoAqAaIAIgAkG0AWogECgCBCAQKAKUASAQKAKYARDuAkUNERBpIU0gBUEANgKwGiAFKAKcBiIBIBAoAgQiAiABIAJIGyIGQQFGBEAgBUEB/h4CsBoiASAFKAKcBk4NBANAAkAgBSgCnBoiAiABQdgUbGoiAS0AsAINACABLQCxAg0AIAUqAqAGIU4gBSgCoBohPiAFQegAaiIEIBBBtAH8CgAAID4gAiABQdABaiAEIE4QigILIAVBAf4eArAaIgEgBSgCnAZIDQALDAQLIAVBADYC0AYgBUIANwLIBiAGQQFrIgNBgICAgARPDRYgBSADQQJ0IgEQMiIENgLIBiAFIAEgBGoiBzYC0AZBACECIARBACAB/AsAIAUgBzYCzAYgA0UNAgNAQQQQMhCaAiEHQRwQMiIBIBA2AhQgASAHNgIAIAEgBUGgBmo2AhggASAFQaAaajYCECABIAVBnBpqNgIMIAEgBUGcBmo2AgggASAFQbAaajYCBCAFQaQaaiIHQdUAIAEQ9gENAiAEIAJBAnRqIgEoAgANASABIAUoAqQaNgIAIAVBADYCpBogBxC4ARogAyACQQFqIgJHDQALDAILEJkCAAsQRgALIAVBAf4eArAaIgEgBSgCnAZIBEADQAJAIAUoApwaIgIgAUHYFGxqIgEtALACDQAgAS0AsQINACAFKgKgBiFOIAUoAqAaIT8gBUGcAmoiByAQQbQB/AoAACA/IAIgAUHQAWogByBOEIoCCyAFQQH+HgKwGiIBIAUoApwGSA0ACwtBACEBIAUoAsgGIQIgBkEBSgRAA0AgAiABQQJ0ahCdAiABQQFqIgEgA0cNAAsLIAJFDQAgAiAFKALMBiIBRwRAA0AgAUEEaxC4ASIBIAJHDQALCyACEC8LEGkhTCAFKAKcGiIBIAEpAwAgTCBNfXw3AwAgFSAuRw0ACwsgBSgCnAYhAgtBACEORAAAAAAAAPD/IUQgAkEASgRAA0ACQCAFKAKcGiAOQdgUbGoiASINLQCwAg0AAkAgAUHQAWoiBigCDCIIIAYoAgQgBigCACICa0EwbSIBSwRAIAYgCCABaxDSBCAGKAIMIQgMAQsgASAITQ0AIAYgAiAIQTBsajYCBAsCQCAIRQ0AAkAgCEEATARARAAAAAAAAAAAIUMMAQsgBigCACECQQAhA0QAAAAAAAAAACFDQQAhASAIQQRPBEAgCEF8cSEHQQAhBANAIEMgAiABQTBsaioCDLugIAIgAUEBckEwbGoqAgy7oCACIAFBAnJBMGxqKgIMu6AgAiABQQNyQTBsaioCDLugIUMgAUEEaiEBIARBBGoiBCAHRw0ACwsgCEEDcSIERQ0AA0AgQyACIAFBMGxqKgIMu6AhQyABQQFqIQEgA0EBaiIDIARHDQALCyAQKgJcIU4gBiBDOQMYIAYgQyAItyJCoyJFOQMgIAYgTkMAAAAAXgR8IEMgQkQAAAAAAAAUQKBEAAAAAAAAGECjIE67EM0CowUgRQs5AzAgBSALNgLIBiAFQgA3AswGRAAAAAAAAAAAIUNBACEPQQAhCQJAQSAgCCAIQSBMG0EgayIMIAhODQADQCAGKAIAIAxBMGxqKAIAIQMgCyIEIQECfwJAAkAgBSgCzAYiAkUNAANAIAIiASgCECICIANKBEAgASEEIAEoAgAiAg0BDAILIAIgA04NAiABKAIEIgINAAsgAUEEaiEEC0EYEDIiCCADNgIQIAggATYCCCAIQgA3AgAgCEEANgIUIAQgCDYCACAIIQMgBSgCyAYoAgAiAQRAIAUgATYCyAYgBCgCACEDCyADIAMgBSgCzAYiB0YiAToADAJAIAENAANAIAMoAggiAi0ADA0BAkAgAiACKAIIIgEoAgAiBEYEQAJAIAEoAgQiBEUNACAELQAMDQAMAgsCQCADIAIoAgBGBEAgAiEDDAELIAIgAigCBCIDKAIAIgQ2AgQgAyAEBH8gBCACNgIIIAIoAggFIAELNgIIIAIoAggiASABKAIAIAJHQQJ0aiADNgIAIAMgAjYCACACIAM2AgggAygCCCIBKAIAIQILIANBAToADCABQQA6AAwgASACKAIEIgM2AgAgAwRAIAMgATYCCAsgAiABKAIINgIIIAEoAggiAyADKAIAIAFHQQJ0aiACNgIAIAIgATYCBCABIAI2AggMAwsCQCAERQ0AIAQtAAwNAAwBCwJAIAMgAigCAEcEQCACIQMMAQsgAiADKAIEIgQ2AgAgAyAEBH8gBCACNgIIIAIoAggFIAELNgIIIAIoAggiASABKAIAIAJHQQJ0aiADNgIAIAMgAjYCBCACIAM2AgggAygCCCEBCyADQQE6AAwgAUEAOgAMIAEgASgCBCICKAIAIgM2AgQgAwRAIAMgATYCCAsgAiABKAIINgIIIAEoAggiAyADKAIAIAFHQQJ0aiACNgIAIAIgATYCACABIAI2AggMAgsgAkEBOgAMIAEgASAHRjoADCAEQQE6AAwgByABIgNHDQALCyAFIA9BAWoiDzYC0AZBAAwBCyABIggoAhQLIQEgCCABQQFqNgIUIAlBAWohCSAMQQFqIgwgBigCDEgNAAsgBSgCyAYiAyALRg0AIAm3IUkDQCADKAIUtyBJoyJCAnwgQr0iTUIwiKchASBNQoCAgICAgID3P31C//////+fwgFYBEBEAAAAAAAAAAAgTUKAgICAgICA+D9RDQEaIEJEAAAAAAAA8L+gIkIgQiBCRAAAAAAAAKBBoiJFoCBFoSJFIEWiQdD9ASsDACJIoiJKoCJLIEIgQiBCoiJGoiJHIEcgRyBHQaD+ASsDAKIgRkGY/gErAwCiIEJBkP4BKwMAokGI/gErAwCgoKCiIEZBgP4BKwMAoiBCQfj9ASsDAKJB8P0BKwMAoKCgoiBGQej9ASsDAKIgQkHg/QErAwCiQdj9ASsDAKCgoKIgQiBFoSBIoiBCIEWgoiBKIEIgS6GgoKCgDAELAkAgAUHw/wFrQZ+Afk0EQCBNQv///////////wCDUARAIwBBEGsiAUQAAAAAAADwvzkDCCABKwMIRAAAAAAAAAAAowwDCyBNQoCAgICAgID4/wBRDQEgAUHw/wFxQfD/AUcgAUH//wFNcUUEQCBCIEKhIkIgQqMMAwsgQkQAAAAAAAAwQ6K9QoCAgICAgICgA30hTQsgTUKAgICAgICA8z99IkxCNIentyJGQZj9ASsDAKIgTEItiKdB/wBxQQR0IgFBsP4BaisDAKAiRyABQaj+AWorAwAgTSBMQoCAgICAgIB4g32/IAFBqI4CaisDAKEgAUGwjgJqKwMAoaIiQqAiSCBCIEIgQqIiRaIgRSBCQcj9ASsDAKJBwP0BKwMAoKIgQkG4/QErAwCiQbD9ASsDAKCgoiBFQaj9ASsDAKIgRkGg/QErAwCiIEIgRyBIoaCgoKCgIUILIEILoiFCAkAgAygCBCICBEADQCACIgEoAgAiAg0ADAILAAsDQCADKAIIIgEoAgAgA0chQCABIQMgQA0ACwsgQyBCoSFDIAsgASIDRw0ACwsgBiBDOQMoIAVByAZqIAUoAswGEOgCIAYoAgxBIUgNACAGKwMoIBAqAmS7Y0UNACANQQE6ALACIAUoApwaIgEgASgCSEEBajYCSAwBCyAOICIgRCAGKwMwIkNjIgEbISIgQyBEIAEbIUQLIA5BAWoiDiAFKAKcBkgNAAsLIBwgBSgClBogBSgCkBoiAmtBAnUiA0EBa0YNASAFKAKcGiIBICJB2BRsaiIELQCwAkUEQCAEKwPwASAQKgJou2NFDQILIAEgASgCREEBajYCRCAcQQFqIhwgA0gNAAsLIAUoApwaICJB2BRsaiIMKALcASEHIAwoAqwCIQ4gGCAYKAKcqAEiATYCoKgBIAUoArAGIgIoAgAgBSgCoBooAvABRgRAIB4gASACQQRqIAUoArQGIAUoArwGIAUoAsAGa2oQ6gILQQAhCCAHQQBMDQEDQCAMKALQASAIQTBsaiEJAkAgGCgCoKgBIgEgGCgCpKgBRwRAIAEgCSgCADYCACAYIAFBBGo2AqCoAQwBCyABIB4oAgAiA2siBEECdSIRQQFqIgJBgICAgARPDQhB/////wMgBEEBdSIGIAIgAiAGSRsgBEH8////B08bIgYEfyAGQYCAgIAETw0KIAZBAnQQMgVBAAsiDSARQQJ0aiICIAkoAgA2AgAgDSAGQQJ0aiEJIAJBBGohEQJAIAEgA0YNAAJAIARBBGsiBkEsSQ0AIAEgBCANamtBEEkNACACQRBrIQ0gAUEQayEVIAEgBkECdkEBaiIUQfz///8HcSIGQQJ0IgRrIQEgAiAEayECQQAhBANAIA0gBEECdCIPayAVIA9r/QACAP0LAgAgBEEEaiIEIAZHDQALIAYgFEYNAQsDQCACQQRrIgIgAUEEayIBKAIANgIAIAEgA0cNAAsLIBggCTYCpKgBIBggETYCoKgBIBggAjYCnKgBIANFDQAgAxAvCyAHIAhBAWoiCEcNAAsMAQsgBUHFIDYCwAVBAkGT5wAgBUHABWoQNAwICwJAIAwoAtABIgEgDCgC1AFGDQAgBSgCoBoiAigCsAFBAEwNACACKAL8ASECIAEoAgQhQUEAIQQgBUG4GmoiDUEANgIAIAVCADcDsBogQSACa0EBdCATaiEJQQAhAkEAIQNBACEIQQAhBwJAIAwoAtQBIAwoAtABIgFrQQBKBH8DQCABIARBMGwiBmooAgAhAiAFKAKgGiEDAkAgEC0AGEUEQCACIAMoAtwBTg0BCwJAAkAgAygC1AEiAUUNAANAIAIgASgCECIDSARAIAEoAgAiAQ0BDAILIAIgA0wNAiABKAIEIgENAAsLQfEjELcBAAsgBUGwGmogAUEUaiICKAIAIAIgASwAH0EASBsQNxogDCgC0AEhAQsgASAGaiIGKAIAIQIgBSgCoBohAyAQLQA8BEAgAiADKALsAUYgCHIhCAsCQAJAIAIgAygC/AEiA0oEQCAQLQAXRQ0BCyAMKALUASABa0EwbSECIAkhBgwBCyAGKAIEIANrQQF0IBNqIQYCQCAFKAK0GiAFLQC7GiIBIAHAQQBIIgMbRQ0AIAYgEC0ANCICdCEBIAkgAnQhAgJAIBAtABpFDQAgEC0AGwRAIAVByAZqIgMgAqwQiAIgBSgCyAYhCSAFLADTBiERIAVBpBpqIhUgAawQiAIgBSAJIAMgEUEASBs2AlAgBSAFKAKkGiAVIAUsAK8aQQBIGzYCVCAFIAUoArAaIAVBsBpqIAUsALsaQQBIGzYCWEHj5AAgBUHQAGoQswEgBSwArxpBAEgEQCAFKAKkGhAvCyAFLADTBkEATg0BIAUoAsgGEC8MAQsgBSAFKAKwGiAFQbAaaiADGzYCQEG5EyAFQUBrELMBICcQMBoLIAUgAaw3A9AGIAUgAqw3A8gGAkAgBSwAuxpBAE4EQCAWIAUpA7AaNwIAIBYgDSgCADYCCAwBCyAWIAUoArAaIAUoArQaEGsLIAVBADYC7AYgBUIANwLkBiAFIAhBAXE6APAGAkAgGygClKgBIgEgGygCmKgBSQRAIAEgBf0AA8gG/QsDACABIBYpAwA3AxAgASAWKAIINgIYIBZBADYCCCAWQgA3AwAgAUEANgIkIAFCADcCHCABIAUoAuQGNgIcIAEgBSgC6AY2AiAgASAFKALsBjYCJCAFQQA2AuwGIAVCADcC5AYgASAFLQDwBjoAKCAbIAFBMGo2ApSoAQwBCyAmIAVByAZqEOcCIAUoAuQGIgFFDQAgBSABNgLoBiABEC8LIAUsAOMGQQBIBEAgBSgC2AYQLwsCQCAEIAdIDQADQAJAIAwoAtABIAciA0EwbGohBwJAIBsoApSoASICQTBrIggoAiAiASAIKAIkRwRAIAEgB/0AAwD9CwMAIAEgB/0AAyD9CwMgIAEgB/0AAxD9CwMQIAggAUEwajYCIAwBCyABIAJBFGsiESgCACIVa0EwbSICQQFqIglB1qrVKk8NAUHVqtUqIAJBAXQiFCAJIAkgFEkbIAJBqtWqFU8bIgkEfyAJQdaq1SpPDRAgCUEwbBAyBUEACyIUIAJBMGxqIgIgB/0AAwD9CwMAIAIgB/0AAyD9CwMgIAIgB/0AAxD9CwMQIAJBMGohByABIBVHBEADQCACQTBrIgIgAUEwayIB/QADAP0LAwAgAiAB/QADIP0LAyAgAiAB/QADEP0LAxAgASAVRw0ACyARKAIAIQELIBEgAjYCACAIIAc2AiAgCCAUIAlBMGxqNgIkIAFFDQAgARAvCyADQQFqIQcgAyAERw0BDAILCwwSCwJ/QQEgEC0AHEUNABogBSgCoBogBSgCnBogGygClKgBIBsoApCoAWtBMG1BAWsgECoCICAQKgIkENEEQQEgECgCKCIBQQBMDQAaIAUoAqAaIAUoApwaIAEgEC0ALBDQBAshASAQKAJ8IgJFDQAgBSgCoBogBSgCnBogASAQKAKAASACEQYACwJ/IAUsALsaQQBIBEAgBUEANgK0GiAFKAKwGgwBCyAFQQA6ALsaIAVBsBpqC0EAOgAAAn8gBCAMKALUASAMKALQASIBa0EwbSICIARMDQAaIAUoAqAaKAL8ASEDA0AgBCADIAEgBEEwbGooAgBODQEaIARBAWoiBCACRw0ACyACCyIHQQFrIQRBACEIIAYhCQsgBEEBaiIEIAJIDQALIAUtALsaIQIgBiEJIAghAyAFKAK0GgVBAAsgAkH/AXEgAsBBAEgiBBtFDQAgDiATaiAQLQA0IgJ0IQEgCSACdCECAkAgEC0AGkUNACAQLQAbBEAgBUHIBmoiBCACrBCIAiAFKALIBiEGIAUsANMGIQggBUGkGmoiCSABrBCIAiAFIAYgBCAIQQBIGzYCMCAFIAUoAqQaIAkgBSwArxpBAEgbNgI0IAUgBSgCsBogBUGwGmogBSwAuxpBAEgbNgI4QePkACAFQTBqELMBIAUsAK8aQQBIBEAgBSgCpBoQLwsgBSwA0wZBAE4NASAFKALIBhAvDAELIAUgBSgCsBogBUGwGmogBBs2AiBBuRMgBUEgahCzASAnEDAaCyAFIAGsNwPQBiAFIAKsNwPIBgJAIAUsALsaQQBOBEAgFiAFKQOwGjcCACAWIA0oAgA2AggMAQsgFiAFKAKwGiAFKAK0GhBrCyAFQQA2AuwGIAVCADcC5AYgBSADQQFxOgDwBgJAIBsoApSoASIBIBsoApioAUkEQCABIAX9AAPIBv0LAwAgASAWKQMANwMQIAEgFigCCDYCGCAWQQA2AgggFkIANwMAIAFBADYCJCABQgA3AhwgASAFKALkBjYCHCABIAUoAugGNgIgIAEgBSgC7AY2AiQgBUEANgLsBiAFQgA3AuQGIAEgBS0A8AY6ACggGyABQTBqNgKUqAEMAQsgJiAFQcgGahDnAiAFKALkBiIBRQ0AIAUgATYC6AYgARAvCyAFLADjBkEASARAIAUoAtgGEC8LAkAgByAMKALUASAMKALQASIBa0EwbU4NAANAAkAgASAHQTBsaiEDAkAgGygClKgBIgJBMGsiBCgCICIBIAQoAiRHBEAgASAD/QADAP0LAwAgASAD/QADIP0LAyAgASAD/QADEP0LAxAgBCABQTBqNgIgDAELIAEgAkEUayIIKAIAIglrQTBtIgJBAWoiBkHWqtUqTw0BQdWq1SogAkEBdCINIAYgBiANSRsgAkGq1aoVTxsiBgR/IAZB1qrVKk8NDCAGQTBsEDIFQQALIg0gAkEwbGoiAiAD/QADAP0LAwAgAiAD/QADIP0LAyAgAiAD/QADEP0LAxAgAkEwaiEDIAEgCUcEQANAIAJBMGsiAiABQTBrIgH9AAMA/QsDACACIAH9AAMg/QsDICACIAH9AAMQ/QsDECABIAlHDQALIAgoAgAhAQsgCCACNgIAIAQgAzYCICAEIA0gBkEwbGo2AiQgAUUNACABEC8LIAdBAWoiByAMKALUASAMKALQASIBa0EwbUgNAQwCCwsMDgsCf0EBIBAtABxFDQAaIAUoAqAaIAUoApwaIBsoApSoASAbKAKQqAFrQTBtQQFrIBAqAiAgECoCJBDRBEEBIBAoAigiAUEATA0AGiAFKAKgGiAFKAKcGiABIBAtACwQ0AQLIQEgECgCfCICRQ0AIAUoAqAaIAUoApwaIAEgECgCgAEgAhEGAAsgBSwAuxpBAE4NACAFKAKwGhAvCyAOIBNqIRMMAAsACwwJCwwICwwHCwwGCxBHAAsgBUHFIDYC0ANBAkGN6gAgBUHQA2oQNAsgGgRAIAogGkcEQANAIApB6ABrIgQoAlQiAwRAIApBEGsiBygCACICIAMiAUcEQANAIAJBDGsiASgCACIGBEAgAkEIayAGNgIAIAYQLwsgASICIANHDQALIAQoAlQhAQsgByADNgIAIAEQLwsgCkEgayIHKAIAIgMEQCAKQRxrIggoAgAiAiADIgFHBEADQCACQQxrIgEoAgAiBgRAIAJBCGsgBjYCACAGEC8LIAEiAiADRw0ACyAHKAIAIQELIAggAzYCACABEC8LIApB2ABrKAIAIgEEQCAKQdQAayABNgIAIAEQLwsgBCIKIBpHDQALCyAaEC8LIAUoAqQGIgMEQCAFKAKoBiIBIAMiAkcEQANAIAFBDGsiCigCACIEBEAgAUEIayIJKAIAIgcgBCICRwRAA0AgB0HoAGsiCCgCVCIGBEAgB0EQayIOKAIAIgIgBiIBRwRAA0AgAkEMayIBKAIAIgwEQCACQQhrIAw2AgAgDBAvCyABIgIgBkcNAAsgCCgCVCEBCyAOIAY2AgAgARAvCyAHQSBrIg4oAgAiBgRAIAdBHGsiDSgCACICIAYiAUcEQANAIAJBDGsiASgCACIMBEAgAkEIayAMNgIAIAwQLwsgASICIAZHDQALIA4oAgAhAQsgDSAGNgIAIAEQLwsgB0HYAGsoAgAiAQRAIAdB1ABrIAE2AgAgARAvCyAIIgcgBEcNAAsgCigCACECCyAJIAQ2AgAgAhAvCyAKIgEgA0cNAAsgBSgCpAYhAgsgBSADNgKoBiACEC8LIAUoArAGIgEEQCAFIAE2ArQGIAEQLwsgBSgCvAYiAUUNACAFIAE2AsAGIAEQLwsgBSgCkBoiAUUNACABEC8LIAVBwBpqJAAgLEHAAWokAEHQuwMoAgAhAiMAQeABayIBJAAQaSFNQQRB4PkAQQAQNCACKQMAIUwgAUGAETYC0AEgASBMtEMAAHpElbs5A9gBQQRB6+MAIAFB0AFqEDQgAigCgAIiAwRAIAMoAkAhBCADKAI8IQYgAygCOCEKIAMoAjQhByADKAIwIQggASADKQJENwLEASABQYARNgLAAUEEQaHmACABQcABahA0IAIoAoACKQMoIUwgAUGAETYCsAEgASBMtEMAAHpElbs5A7gBQQRBr+MAIAFBsAFqEDQgAigCgAIpAwAhTCABQQEgCCAIQQFMGyIDNgKgASABIEy0Q28SgzqUIk4gA7KVuzkDqAEgAUGAETYCkAEgASBOuzkDmAFBBEGb9QAgAUGQAWoQNCACKAKAAikDCCFMIAFBASAHIAdBAUwbIgM2AoABIAEgTLRDbxKDOpQiTiADspW7OQOIASABQYARNgJwIAEgTrs5A3hBBEHX9QAgAUHwAGoQNCACKAKAAikDECFMIAFBASAKIApBAUwbIgM2AmAgASBMtENvEoM6lCJOIAOylbs5A2ggAUGAETYCUCABIE67OQNYQQRBk/YAIAFB0ABqEDQgAigCgAIpAxghTCABQUBrQQEgBiAGQQFMGyIDNgIAIAEgTLRDbxKDOpQiTiADspW7OQNIIAFBgBE2AjAgASBOuzkDOEEEQc/2ACABQTBqEDQgAigCgAIpAyAhTCABQQEgBCAEQQFMGyIDNgIgIAEgTLRDbxKDOpQiTiADspW7OQMoIAFBgBE2AhAgASBOuzkDGEEEQd/0ACABQRBqEDQLIAIpAwghTCABQYARNgIAIAEgTSBMfbRDAAB6RJW7OQMIQQRBzeMAIAEQNCABQeABaiQAICsQBCApEAQgLxAEIBIoAvgBIgFFDQAgEiABNgL8ASABEC8LIBJB0ANqJAAgAA8LEDYACxsAQaCRNSEAA0AgAEEMaxAzIgBBgI81Rw0ACwuqAgACQEH4ijX+EgAAQQFxDQBB+Io1EFRFDQACQEGgkTX+EgAAQQFxDQBBoJE1EFRFDQBBoJE1EFMLQYCPNUHqCBBBQYyPNUHhCBBBQZiPNUH7HBBBQaSPNUGqGhBBQbCPNUG2CRBBQbyPNUHZIhBBQciPNUHyCBBBQdSPNUHXChBBQeCPNUHhFBBBQeyPNUHQFBBBQfiPNUHYFBBBQYSQNUHrFBBBQZCQNUHOGRBBQZyQNUGdKBBBQaiQNUGgFRBBQbSQNUHSExBBQcCQNUG2CRBBQcyQNUGhFhBBQdiQNUHpGRBBQeSQNUGOHRBBQfCQNUHsFRBBQfyQNUHODxBBQYiRNUG+ChBBQZSRNUHgJhBBQfSKNUGAjzU2AgBB+Io1EFMLQfSKNSgCAAsbAEH4jjUhAANAIABBDGsQUCIAQdCNNUcNAAsL3gEAAkBB8Io1/hIAAEEBcQ0AQfCKNRBURQ0AAkBB+I41/hIAAEEBcQ0AQfiONRBURQ0AQfiONRBTC0HQjTVB9JgDEEBB3I01QZCZAxBAQeiNNUGsmQMQQEH0jTVBzJkDEEBBgI41QfSZAxBAQYyONUGYmgMQQEGYjjVBtJoDEEBBpI41QdiaAxBAQbCONUHomgMQQEG8jjVB+JoDEEBByI41QYibAxBAQdSONUGYmwMQQEHgjjVBqJsDEEBB7I41QbibAxBAQeyKNUHQjTU2AgBB8Io1EFMLQeyKNSgCAAsbAEHIjTUhAANAIABBDGsQMyIAQaCMNUcNAAsL0AEAAkBB6Io1/hIAAEEBcQ0AQeiKNRBURQ0AAkBByI01/hIAAEEBcQ0AQciNNRBURQ0AQciNNRBTC0GgjDVBoQkQQUGsjDVBqAkQQUG4jDVBhgkQQUHEjDVBjgkQQUHQjDVB/QgQQUHcjDVBrwkQQUHojDVBmAkQQUH0jDVBnRYQQUGAjTVBixcQQUGMjTVBvB8QQUGYjTVBxCUQQUGkjTVBzAoQQUGwjTVBrBsQQUG8jTVB2A8QQUHkijVBoIw1NgIAQeiKNRBTC0HkijUoAgALCwAgAEGk9gIQugELCwAgAEGbIRCmARoLCwAgAEGQ9gIQugELCwAgAEGYHxCmARoLDAAgACABQRBqEOcBCwwAIAAgAUEMahDnAQsHACAALAAJCwcAIAAsAAgLDAAgABCgAxogABAvCwwAIAAQoQMaIAAQLwsVACAAKAIIIgBFBEBBAQ8LIAAQqAMLkQEBB38DQAJAIAQgCE0NACACIANGDQBBASEHIAAoAgghBSMAQRBrIgYkACAGIAU2AgwgBkEIaiAGQQxqEH8hC0EAIAIgAyACayABQcyINSABGxDwASEFIAsQfiAGQRBqJAACQAJAIAVBAmoOAwICAQALIAUhBwsgCEEBaiEIIAcgCWohCSACIAdqIQIMAQsLIAkLRgECfyAAKAIIIQIjAEEQayIBJAAgASACNgIMIAFBCGogAUEMahB/EH4gAUEQaiQAIAAoAggiAEUEQEEBDwsgABCoA0EBRguNAQEDfyMAQRBrIgYkACAEIAI2AgACf0ECIAZBDGoiBUEAIAAoAggQrAIiAEEBakECSQ0AGkEBIABBAWsiAiADIAQoAgBrSw0AGgN/IAIEfyAFLQAAIQAgBCAEKAIAIgFBAWo2AgAgASAAOgAAIAJBAWshAiAFQQFqIQUMAQVBAAsLCyEHIAZBEGokACAHC+IGAQ9/IwBBEGsiESQAIAIhCANAAkAgAyAIRgRAIAMhCAwBCyAILQAARQ0AIAhBAWohCAwBCwsgByAFNgIAIAQgAjYCAANAAkACfwJAIAIgA0YNACAFIAZGDQAgESABKQIANwMIIAAoAgghCiMAQRBrIhAkACAQIAo2AgwgEEEIaiAQQQxqEH8hFSAIIAJrIQ5BACELIwBBkAhrIg0kACANIAQoAgAiCjYCDCAGIAVrQQJ1QYACIAUbIQwgBSANQRBqIAUbIQ8CQAJAAkACQCAKRQ0AIAxFDQADQCAOQQJ2IQkCQCAOQYMBSw0AIAkgDE8NACAKIQkMBAsgDyANQQxqIAkgDCAJIAxJGyABEOIDIRIgDSgCDCEJIBJBf0YEQEEAIQxBfyELDAMLIAwgEkEAIA8gDUEQakcbIhRrIQwgDyAUQQJ0aiEPIAogDmogCWtBACAJGyEOIAsgEmohCyAJRQ0CIAkhCiAMDQALDAELIAohCQsgCUUNAQsgDEUNACAORQ0AIAshCgNAAkACQCAPIAkgDiABEPABIgtBAmpBAk0EQAJAAkAgC0EBag4CBgABCyANQQA2AgwMAgsgAUEANgIADAELIA0gDSgCDCALaiIJNgIMIApBAWohCiAMQQFrIgwNAQsgCiELDAILIA9BBGohDyAOIAtrIQ4gCiELIA4NAAsLIAUEQCAEIA0oAgw2AgALIA1BkAhqJAAgFRB+IBBBEGokAAJAAkACQAJAIAtBf0YEQANAAkAgByAFNgIAIAIgBCgCAEYNAEEBIQYCQAJAAkAgBSACIAggAmsgEUEIaiAAKAIIEKkDIgFBAmoOAwgAAgELIAQgAjYCAAwFCyABIQYLIAIgBmohAiAHKAIAQQRqIQUMAQsLIAQgAjYCAAwFCyAHIAcoAgAgC0ECdGoiBTYCACAFIAZGDQMgBCgCACECIAMgCEYEQCADIQgMCAsgBSACQQEgASAAKAIIEKkDRQ0BC0ECDAQLIAcgBygCAEEEajYCACAEIAQoAgBBAWoiAjYCACACIQgDQCADIAhGBEAgAyEIDAYLIAgtAABFDQUgCEEBaiEIDAALAAsgBCACNgIAQQEMAgsgBCgCACECCyACIANHCyEWIBFBEGokACAWDwsgBygCACEFDAALAAu4BQENfyMAQRBrIg4kACACIQgDQAJAIAMgCEYEQCADIQgMAQsgCCgCAEUNACAIQQRqIQgMAQsLIAcgBTYCACAEIAI2AgADQAJAAkACQCACIANGDQAgBSAGRg0AIA4gASkCADcDCEEBIRAgACgCCCEJIwBBEGsiDyQAIA8gCTYCDCAPQQhqIA9BDGoQfyEUIAUhCSAIIAJrQQJ1IREgBiAFayEKQQAhDCMAQRBrIhIkAAJAIAQoAgAiC0UNACARRQ0AIApBACAFGyEKA0AgEkEMaiAJIApBBEkbIAsoAgAQwgIiDUF/RgRAQX8hDAwCCyAJBH8gCkEDTQRAIAogDUkNAyAJIBJBDGogDRB7GgsgCiANayEKIAkgDWoFQQALIQkgCygCAEUEQEEAIQsMAgsgDCANaiEMIAtBBGohCyARQQFrIhENAAsLIAkEQCAEIAs2AgALIBJBEGokACAUEH4gD0EQaiQAAkACQAJAAkACQCAMQQFqDgIABgELIAcgBTYCAANAAkAgAiAEKAIARg0AIAUgAigCACAAKAIIEKwCIgFBf0YNACAHIAcoAgAgAWoiBTYCACACQQRqIQIMAQsLIAQgAjYCAAwBCyAHIAcoAgAgDGoiBTYCACAFIAZGDQIgAyAIRgRAIAQoAgAhAiADIQgMBwsgDkEEakEAIAAoAggQrAIiCEF/Rw0BC0ECIRAMAwsgDkEEaiECIAYgBygCAGsgCEkNAgNAIAgEQCACLQAAIQUgByAHKAIAIglBAWo2AgAgCSAFOgAAIAhBAWshCCACQQFqIQIMAQsLIAQgBCgCAEEEaiICNgIAIAIhCANAIAMgCEYEQCADIQgMBQsgCCgCAEUNBCAIQQRqIQgMAAsACyAEKAIAIQILIAIgA0chEAsgDkEQaiQAIBAPCyAHKAIAIQUMAAsACwwAIAAQsgMaIAAQLwtaAQF/IwBBEGsiACQAIAAgBDYCDCAAIAMgAms2AggjAEEQayIBJAAgAEEIaiICKAIAIABBDGoiAygCAEkhBCABQRBqJAAgAiADIAQbKAIAIQUgAEEQaiQAIAULNAADQCABIAJGRQRAIAQgAyABLAAAIgAgAEEASBs6AAAgBEEBaiEEIAFBAWohAQwBCwsgAgsMACACIAEgAUEASBsLKgADQCABIAJGRQRAIAMgAS0AADoAACADQQFqIQMgAUEBaiEBDAELCyACCz0AA0AgASACRwRAIAEgASwAACIAQQBOBH9BwN4CKAIAIABBAnRqKAIABSAACzoAACABQQFqIQEMAQsLIAILIgAgAUEATgR/QcDeAigCACABQf8BcUECdGooAgAFIAELwAs9AANAIAEgAkcEQCABIAEsAAAiAEEATgR/QbjSAigCACAAQQJ0aigCAAUgAAs6AAAgAUEBaiEBDAELCyACCyIAIAFBAE4Ef0G40gIoAgAgAUH/AXFBAnRqKAIABSABC8ALDAAgABCrAxogABAvCzUAA0AgASACRkUEQCAEIAEoAgAiACADIABBgAFJGzoAACAEQQFqIQQgAUEEaiEBDAELCyACCw4AIAEgAiABQYABSRvACyoAA0AgASACRkUEQCADIAEsAAA2AgAgA0EEaiEDIAFBAWohAQwBCwsgAgs+AANAIAEgAkcEQCABIAEoAgAiAEH/AE0Ef0HA3gIoAgAgAEECdGooAgAFIAALNgIAIAFBBGohAQwBCwsgAgseACABQf8ATQR/QcDeAigCACABQQJ0aigCAAUgAQsLPgADQCABIAJHBEAgASABKAIAIgBB/wBNBH9BuNICKAIAIABBAnRqKAIABSAACzYCACABQQRqIQEMAQsLIAILHgAgAUH/AE0Ef0G40gIoAgAgAUECdGooAgAFIAELC0EAAkADQCACIANGDQECQCACKAIAIgBB/wBLDQAgAEECdEGQ7QJqKAIAIAFxRQ0AIAJBBGohAgwBCwsgAiEDCyADC0AAA0ACQCACIANHBH8gAigCACIAQf8ASw0BIABBAnRBkO0CaigCACABcUUNASACBSADCw8LIAJBBGohAgwACwALSQEBfwNAIAEgAkZFBEBBACEAIAMgASgCACIEQf8ATQR/IARBAnRBkO0CaigCAAVBAAs2AgAgA0EEaiEDIAFBBGohAQwBCwsgAgslAEEAIQAgAkH/AE0EfyACQQJ0QZDtAmooAgAgAXFBAEcFQQALCw8AIAAgACgCACgCBBEBAAsUACAAQQBBAf4eApCKNUEBajYCBAsMACAAEK8DGiAAEC8LsBEBA39B7JY1QQA2AgBB6JY1QbigAzYCAEHoljVBkPgCNgIAQeiWNUHI7AI2AgAjAEEQayIAJABB8JY1QgA3AwAgAEEANgIMQfiWNUEANgIAQfiXNUEAOgAAIABB8JY1NgIEIAAoAgQaIABBADoACiMAQRBrIgEkAEHwljUQmANBHkkEQBA2AAsgAUEIakGAlzVBHhCXA0H0ljUgASgCCCICNgIAQfCWNSACNgIAQfiWNSACIAEoAgxBAnRqNgIAQfiWNSgCABpB8JY1KAIAGiABQRBqJABB8JY1QR4QsQMgAEEBOgAKIABBEGokAEGAmDVB5TMQpgEaQfSWNSgCABpB8JY1KAIAGkHwljUQsANB+JY1KAIAGkH0ljUoAgAaQfCWNSgCABpBpJQ1QQA2AgBBoJQ1QbigAzYCAEGglDVBkPgCNgIAQaCUNUHkgAM2AgBB6JY1QaCUNUHQiDUQTBBOQayUNUEANgIAQaiUNUG4oAM2AgBBqJQ1QZD4AjYCAEGolDVBhIEDNgIAQeiWNUGolDVB2Ig1EEwQTkG0lDVBADYCAEGwlDVBuKADNgIAQbCUNUGQ+AI2AgBBvJQ1QQA6AABBuJQ1QQA2AgBBsJQ1QdzsAjYCAEG4lDVBkO0CNgIAQeiWNUGwlDVBnIo1EEwQTkHElDVBADYCAEHAlDVBuKADNgIAQcCUNUGQ+AI2AgBBwJQ1Qcj4AjYCAEHoljVBwJQ1QZSKNRBMEE5BzJQ1QQA2AgBByJQ1QbigAzYCAEHIlDVBkPgCNgIAQciUNUHc+QI2AgBB6JY1QciUNUGkijUQTBBOQdSUNUEANgIAQdCUNUG4oAM2AgBB0JQ1QZD4AjYCAEHQlDVBmPUCNgIAQdiUNRBENgIAQeiWNUHQlDVBrIo1EEwQTkHklDVBADYCAEHglDVBuKADNgIAQeCUNUGQ+AI2AgBB4JQ1QfD6AjYCAEHoljVB4JQ1QbSKNRBMEE5B7JQ1QQA2AgBB6JQ1QbigAzYCAEHolDVBkPgCNgIAQeiUNUHY/AI2AgBB6JY1QeiUNUHEijUQTBBOQfSUNUEANgIAQfCUNUG4oAM2AgBB8JQ1QZD4AjYCAEHwlDVB5PsCNgIAQeiWNUHwlDVBvIo1EEwQTkH8lDVBADYCAEH4lDVBuKADNgIAQfiUNUGQ+AI2AgBB+JQ1Qcz9AjYCAEHoljVB+JQ1QcyKNRBMEE5BhJU1QQA2AgBBgJU1QbigAzYCAEGAlTVBkPgCNgIAQYiVNUGu2AA7AQBBgJU1Qcj1AjYCACMAQRBrIgAkAEGMlTVCADcCAEGUlTVBADYCACAAQRBqJABB6JY1QYCVNUHUijUQTBBOQZyVNUEANgIAQZiVNUG4oAM2AgBBmJU1QZD4AjYCAEGglTVCroCAgMAFNwIAQZiVNUHw9QI2AgAjAEEQayIAJABBqJU1QgA3AgBBsJU1QQA2AgAgAEEQaiQAQeiWNUGYlTVB3Io1EEwQTkG8lTVBADYCAEG4lTVBuKADNgIAQbiVNUGQ+AI2AgBBuJU1QaSBAzYCAEHoljVBuJU1QeCINRBMEE5BxJU1QQA2AgBBwJU1QbigAzYCAEHAlTVBkPgCNgIAQcCVNUGYgwM2AgBB6JY1QcCVNUHoiDUQTBBOQcyVNUEANgIAQciVNUG4oAM2AgBByJU1QZD4AjYCAEHIlTVB7IQDNgIAQeiWNUHIlTVB8Ig1EEwQTkHUlTVBADYCAEHQlTVBuKADNgIAQdCVNUGQ+AI2AgBB0JU1QdSGAzYCAEHoljVB0JU1QfiINRBMEE5B3JU1QQA2AgBB2JU1QbigAzYCAEHYlTVBkPgCNgIAQdiVNUGsjgM2AgBB6JY1QdiVNUGgiTUQTBBOQeSVNUEANgIAQeCVNUG4oAM2AgBB4JU1QZD4AjYCAEHglTVBwI8DNgIAQeiWNUHglTVBqIk1EEwQTkHslTVBADYCAEHolTVBuKADNgIAQeiVNUGQ+AI2AgBB6JU1QbSQAzYCAEHoljVB6JU1QbCJNRBMEE5B9JU1QQA2AgBB8JU1QbigAzYCAEHwlTVBkPgCNgIAQfCVNUGokQM2AgBB6JY1QfCVNUG4iTUQTBBOQfyVNUEANgIAQfiVNUG4oAM2AgBB+JU1QZD4AjYCAEH4lTVBnJIDNgIAQeiWNUH4lTVBwIk1EEwQTkGEljVBADYCAEGAljVBuKADNgIAQYCWNUGQ+AI2AgBBgJY1QcCTAzYCAEHoljVBgJY1QciJNRBMEE5BjJY1QQA2AgBBiJY1QbigAzYCAEGIljVBkPgCNgIAQYiWNUHklAM2AgBB6JY1QYiWNUHQiTUQTBBOQZSWNUEANgIAQZCWNUG4oAM2AgBBkJY1QZD4AjYCAEGQljVBiJYDNgIAQeiWNUGQljVB2Ik1EEwQTkGcljVBADYCAEGYljVBuKADNgIAQZiWNUGQ+AI2AgBBoJY1QfCfAzYCAEGYljVBnIgDNgIAQaCWNUHMiAM2AgBB6JY1QZiWNUGAiTUQTBBOQayWNUEANgIAQaiWNUG4oAM2AgBBqJY1QZD4AjYCAEGwljVBlKADNgIAQaiWNUGkigM2AgBBsJY1QdSKAzYCAEHoljVBqJY1QYiJNRBMEE5BvJY1QQA2AgBBuJY1QbigAzYCAEG4ljVBkPgCNgIAQcCWNRCSA0G4ljVBkIwDNgIAQeiWNUG4ljVBkIk1EEwQTkHMljVBADYCAEHIljVBuKADNgIAQciWNUGQ+AI2AgBB0JY1EJIDQciWNUGsjQM2AgBB6JY1QciWNUGYiTUQTBBOQdyWNUEANgIAQdiWNUG4oAM2AgBB2JY1QZD4AjYCAEHYljVBrJcDNgIAQeiWNUHYljVB4Ik1EEwQTkHkljVBADYCAEHgljVBuKADNgIAQeCWNUGQ+AI2AgBB4JY1QaSYAzYCAEHoljVB4JY1QeiJNRBMEE4LnAIAIwBBEGsiAyQAAkAgBS0AC0EHdkUEQCAAIAUoAgg2AgggACAFKQIANwIADAELIAUoAgAhAiAFKAIEIQUjAEEQayIEJAACQAJAAkAgBUECSQRAIAAiASAALQALQYABcSAFcjoACyAAIAAtAAtB/wBxOgALDAELIAVB7////wNLDQEgBEEIaiAAIAVBAk8EfyAFQQRqQXxxIgEgAUEBayIBIAFBAkYbBUEBC0EBahC5ASAEKAIMGiAAIAQoAggiATYCACAAIAAoAghBgICAgHhxIAQoAgxB/////wdxcjYCCCAAIAAoAghBgICAgHhyNgIIIAAgBTYCBAsgASACIAVBAWoQngEgBEEQaiQADAELEE0ACwsgA0EQaiQACwkAIAAgBRDnAQvfBgEPfyMAQeADayIAJAAgAEHcA2oiBiADKAIcIgc2AgAgB0EEakEB/h4CABogBhBsIQoCfyAFLQALQQd2BEAgBSgCBAwBCyAFLQALQf8AcQsEQAJ/IAUtAAtBB3YEQCAFKAIADAELIAULKAIAIApBLSAKKAIAKAIsEQQARiELCyACIAsgAEHcA2ogAEHYA2ogAEHUA2ohFCAAQdADaiEQIwBBEGsiBiQAIABBxANqIgJCADcCACACQQA2AgggBkEQaiQAIBQgECETIAIiDCEPIwBBEGsiAiQAIABBuANqIgZCADcCACAGQQA2AgggAkEQaiQAIBMgDyESIAYhDiMAQRBrIgIkACAAQawDaiIHQgA3AgAgB0EANgIIIAJBEGokACASIA4gByAAQagDahC2AyAAQfYBNgIQIABBCGpBACAAQRBqIgIQUSEIAkACfwJ/IAUtAAtBB3YEQCAFKAIEDAELIAUtAAtB/wBxCyAAKAKoA0oEQAJ/IAUtAAtBB3YEQCAFKAIEDAELIAUtAAtB/wBxCyEJIAAoAqgDIg0CfyAGLQALQQd2BEAgBigCBAwBCyAGLQALQf8AcQsCfyAHLQALQQd2BEAgBygCBAwBCyAHLQALQf8AcQsgCSANa0EBdGpqakEBagwBCyAAKAKoAwJ/IActAAtBB3YEQCAHKAIEDAELIActAAtB/wBxCwJ/IAYtAAtBB3YEQCAGKAIEDAELIAYtAAtB/wBxC2pqQQJqCyIJQeUASQ0AIAlBAnQQOyEJIAgoAgAhAiAIIAk2AgAgAgRAIAIgCCgCBBEBAAsgCCgCACICDQAQRgALIAIgAEEEaiAAIAMoAgQCfyAFLQALQQd2BEAgBSgCAAwBCyAFCwJ/IAUtAAtBB3YEQCAFKAIADAELIAULAn8gBS0AC0EHdgRAIAUoAgQMAQsgBS0AC0H/AHELQQJ0aiAKIAsgAEHYA2ogACgC1AMgACgC0AMgDCAGIAcgACgCqAMQtQMgASACIAAoAgQgACgCACADIAQQlAEhESAIKAIAIQEgCEEANgIAIAEEQCABIAgoAgQRAQALIAcQUBogBhBQGiAMEDMaIAAoAtwDIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQeADaiQAIBEL6AcBEn8jAEGgCGsiACQAIAAgBTcDECAAIAY3AxggACAAQbAHaiIHNgKsByAHQeQAQbYeIABBEGoQxQIhCSAAQfYBNgKQBCAAQYgEakEAIABBkARqIg4QUSEMIABB9gE2ApAEIABBgARqQQAgDhBRIQoCQCAJQeQATwRAEEQhByAAIAU3AwAgACAGNwMIIABBrAdqIAdBth4gABCLASIJQX9GDQEgDCgCACEHIAwgACgCrAc2AgAgBwRAIAcgDCgCBBEBAAsgCUECdBA7IQggCigCACEHIAogCDYCACAHBEAgByAKKAIEEQEACyAKKAIAIg5FDQELIABB/ANqIgcgAygCHCIINgIAIAhBBGpBAf4eAgAaIAcQbCIRIgcgACgCrAciCCAIIAlqIA4gBygCACgCMBEIABogCUEASgRAIAAoAqwHLQAAQS1GIQ8LIAIgDyAAQfwDaiAAQfgDaiAAQfQDaiEYIABB8ANqIRQjAEEQayIHJAAgAEHkA2oiAkIANwIAIAJBADYCCCAHQRBqJAAgGCAUIRcgAiIQIRMjAEEQayIHJAAgAEHYA2oiAkIANwIAIAJBADYCCCAHQRBqJAAgFyATIRYgAiIHIRIjAEEQayIIJAAgAEHMA2oiAkIANwIAIAJBADYCCCAIQRBqJAAgFiASIAIiCCAAQcgDahC2AyAAQfYBNgIwIABBKGpBACAAQTBqIgIQUSELAn8gACgCyAMiDSAJSARAAn8gBy0AC0EHdgRAIAcoAgQMAQsgBy0AC0H/AHELAn8gCC0AC0EHdgRAIAgoAgQMAQsgCC0AC0H/AHELIAkgDWtBAXRqaiANakEBagwBCyAAKALIAwJ/IAgtAAtBB3YEQCAIKAIEDAELIAgtAAtB/wBxCwJ/IActAAtBB3YEQCAHKAIEDAELIActAAtB/wBxC2pqQQJqCyINQeUATwRAIA1BAnQQOyENIAsoAgAhAiALIA02AgAgAgRAIAIgCygCBBEBAAsgCygCACICRQ0BCyACIABBJGogAEEgaiADKAIEIA4gDiAJQQJ0aiARIA8gAEH4A2ogACgC9AMgACgC8AMgECAHIAggACgCyAMQtQMgASACIAAoAiQgACgCICADIAQQlAEhFSALKAIAIQEgC0EANgIAIAEEQCABIAsoAgQRAQALIAgQUBogBxBQGiAQEDMaIAAoAvwDIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAKKAIAIQEgCkEANgIAIAEEQCABIAooAgQRAQALIAwoAgAhASAMQQA2AgAgAQRAIAEgDCgCBBEBAAsgAEGgCGokACAVDwsQRgAL2QYBD38jAEGwAWsiACQAIABBrAFqIgYgAygCHCIHNgIAIAdBBGpBAf4eAgAaIAYQciEKAn8gBS0AC0EHdgRAIAUoAgQMAQsgBS0AC0H/AHELBEACfyAFLQALQQd2BEAgBSgCAAwBCyAFCy0AACAKQS0gCigCACgCHBEEAEH/AXFGIQsLIAIgCyAAQawBaiAAQagBaiAAQacBaiEUIABBpgFqIRAjAEEQayIGJAAgAEGYAWoiAkIANwIAIAJBADYCCCAGQRBqJAAgFCAQIRMgAiIMIQ8jAEEQayICJAAgAEGMAWoiBkIANwIAIAZBADYCCCACQRBqJAAgEyAPIRIgBiEOIwBBEGsiAiQAIABBgAFqIgdCADcCACAHQQA2AgggAkEQaiQAIBIgDiAHIABB/ABqELkDIABB9gE2AhAgAEEIakEAIABBEGoiAhBRIQgCQAJ/An8gBS0AC0EHdgRAIAUoAgQMAQsgBS0AC0H/AHELIAAoAnxKBEACfyAFLQALQQd2BEAgBSgCBAwBCyAFLQALQf8AcQshCSAAKAJ8Ig0CfyAGLQALQQd2BEAgBigCBAwBCyAGLQALQf8AcQsCfyAHLQALQQd2BEAgBygCBAwBCyAHLQALQf8AcQsgCSANa0EBdGpqakEBagwBCyAAKAJ8An8gBy0AC0EHdgRAIAcoAgQMAQsgBy0AC0H/AHELAn8gBi0AC0EHdgRAIAYoAgQMAQsgBi0AC0H/AHELampBAmoLIglB5QBJDQAgCRA7IQkgCCgCACECIAggCTYCACACBEAgAiAIKAIEEQEACyAIKAIAIgINABBGAAsgAiAAQQRqIAAgAygCBAJ/IAUtAAtBB3YEQCAFKAIADAELIAULAn8gBS0AC0EHdgRAIAUoAgAMAQsgBQsCfyAFLQALQQd2BEAgBSgCBAwBCyAFLQALQf8AcQtqIAogCyAAQagBaiAALACnASAALACmASAMIAYgByAAKAJ8ELgDIAEgAiAAKAIEIAAoAgAgAyAEEJUBIREgCCgCACEBIAhBADYCACABBEAgASAIKAIEEQEACyAHEDMaIAYQMxogDBAzGiAAKAKsASIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgAEGwAWokACARC98HARJ/IwBBwANrIgAkACAAIAU3AxAgACAGNwMYIAAgAEHQAmoiBzYCzAIgB0HkAEG2HiAAQRBqEMUCIQkgAEH2ATYC4AEgAEHYAWpBACAAQeABaiIOEFEhDCAAQfYBNgLgASAAQdABakEAIA4QUSEKAkAgCUHkAE8EQBBEIQcgACAFNwMAIAAgBjcDCCAAQcwCaiAHQbYeIAAQiwEiCUF/Rg0BIAwoAgAhByAMIAAoAswCNgIAIAcEQCAHIAwoAgQRAQALIAkQOyEIIAooAgAhByAKIAg2AgAgBwRAIAcgCigCBBEBAAsgCigCACIORQ0BCyAAQcwBaiIHIAMoAhwiCDYCACAIQQRqQQH+HgIAGiAHEHIiESIHIAAoAswCIgggCCAJaiAOIAcoAgAoAiARCAAaIAlBAEoEQCAAKALMAi0AAEEtRiEPCyACIA8gAEHMAWogAEHIAWogAEHHAWohGCAAQcYBaiEUIwBBEGsiByQAIABBuAFqIgJCADcCACACQQA2AgggB0EQaiQAIBggFCEXIAIiECETIwBBEGsiByQAIABBrAFqIgJCADcCACACQQA2AgggB0EQaiQAIBcgEyEWIAIiByESIwBBEGsiCCQAIABBoAFqIgJCADcCACACQQA2AgggCEEQaiQAIBYgEiACIgggAEGcAWoQuQMgAEH2ATYCMCAAQShqQQAgAEEwaiICEFEhCwJ/IAAoApwBIg0gCUgEQAJ/IActAAtBB3YEQCAHKAIEDAELIActAAtB/wBxCwJ/IAgtAAtBB3YEQCAIKAIEDAELIAgtAAtB/wBxCyAJIA1rQQF0amogDWpBAWoMAQsgACgCnAECfyAILQALQQd2BEAgCCgCBAwBCyAILQALQf8AcQsCfyAHLQALQQd2BEAgBygCBAwBCyAHLQALQf8AcQtqakECagsiDUHlAE8EQCANEDshDSALKAIAIQIgCyANNgIAIAIEQCACIAsoAgQRAQALIAsoAgAiAkUNAQsgAiAAQSRqIABBIGogAygCBCAOIAkgDmogESAPIABByAFqIAAsAMcBIAAsAMYBIBAgByAIIAAoApwBELgDIAEgAiAAKAIkIAAoAiAgAyAEEJUBIRUgCygCACEBIAtBADYCACABBEAgASALKAIEEQEACyAIEDMaIAcQMxogEBAzGiAAKALMASIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgCigCACEBIApBADYCACABBEAgASAKKAIEEQEACyAMKAIAIQEgDEEANgIAIAEEQCABIAwoAgQRAQALIABBwANqJAAgFQ8LEEYAC6UIAQZ/IwBBwANrIgAkACAAIAI2ArgDIAAgATYCvAMgAEH3ATYCFCAAQRhqIABBIGogAEEUaiIHEFEhCSAAQRBqIgggBCgCHCIBNgIAIAFBBGpBAf4eAgAaIAgQbCEBIABBADoADyAAQbwDaiACIAMgCCAEKAIEIAUgAEEPaiABIAkgByAAQbADahC9AwRAIwBBEGsiAiQAAkAgBi0AC0EHdgRAIAYoAgAhCyACQQA2AgwgCyACKAIMNgIAIAZBADYCBAwBCyACQQA2AgggBiACKAIINgIAIAYgBi0AC0GAAXE6AAsgBiAGLQALQf8AcToACwsgAkEQaiQAIAAtAA8EQCAGIAFBLSABKAIAKAIsEQQAEKECCyABQTAgASgCACgCLBEEACEBIAkoAgAhAiAAKAIUIgNBBGshBANAAkAgAiAETw0AIAIoAgAgAUcNACACQQRqIQIMAQsLIwBBEGsiCCQAAn8gBi0AC0EHdgRAIAYoAgQMAQsgBi0AC0H/AHELIQEgBi0AC0EHdgR/IAYoAghB/////wdxQQFrBUEBCyEEAkAgAyACa0ECdSIHRQ0AAn8gBi0AC0EHdgRAIAYoAgAMAQsgBgsgAk0EfwJ/IAYtAAtBB3YEQCAGKAIADAELIAYLAn8gBi0AC0EHdgRAIAYoAgQMAQsgBi0AC0H/AHELQQJ0aiACTwVBAAtFBEAgByAEIAFrSwRAIAYgBCABIARrIAdqIAEgARCGAwsCfyAGLQALQQd2BEAgBigCAAwBCyAGCyABQQJ0aiEEA0AgAiADRwRAIAQgAigCADYCACACQQRqIQIgBEEEaiEEDAELCyAIQQA2AgQgBCAIKAIENgIAIAYgASAHahCZAQwBCyMAQRBrIgQkACAIQQRqIgEgAiADEN4DIARBEGokAAJ/IAEtAAtBB3YEQCABKAIADAELIAELIQcCfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQshAiMAQRBrIgQkAAJAIAIgBi0AC0EHdgR/IAYoAghB/////wdxQQFrBUEBCyIKAn8gBi0AC0EHdgRAIAYoAgQMAQsgBi0AC0H/AHELIgNrTQRAIAJFDQECfyAGLQALQQd2BEAgBigCAAwBCyAGCyIKIANBAnRqIAcgAhCeASAGIAIgA2oiAhCZASAEQQA2AgwgCiACQQJ0aiAEKAIMNgIADAELIAYgCiACIAprIANqIAMgA0EAIAIgBxCHAwsgBEEQaiQAIAEQUBoLIAhBEGokAAsgAEG8A2ogAEG4A2oQQgRAIAUgBSgCAEECcjYCAAsgACgCvAMhDCAAKAIQIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAJKAIAIQEgCUEANgIAIAEEQCABIAkoAgQRAQALIABBwANqJAAgDAvQBAEEfyMAQfAEayIAJAAgACACNgLoBCAAIAE2AuwEIABB9wE2AhAgAEHIAWogAEHQAWogAEEQaiIBEFEhByAAQcABaiIJIAQoAhwiCDYCACAIQQRqQQH+HgIAGiAJEGwhCCAAQQA6AL8BAkAgAEHsBGogAiADIAkgBCgCBCAFIABBvwFqIAggByAAQcQBaiAAQeAEahC9A0UNACAAQZ85KAAANgC3ASAAQZg5KQAANwOwASAIIABBsAFqIABBugFqIABBgAFqIAgoAgAoAjARCAAaIABB9gE2AhAgAEEIakEAIAEQUSEDIAEhBAJAIAAoAsQBIAcoAgBrIgFBiQNOBEAgAUECdUECahA7IQIgAygCACEBIAMgAjYCACABBEAgASADKAIEEQEACyADKAIAIgRFDQELIAAtAL8BBEAgBEEtOgAAIARBAWohBAsgBygCACECA0AgACgCxAEgAk0EQAJAIARBADoAACAAIAY2AgAgAEEQaiAAEOQDQQFHDQAgAygCACEBIANBADYCACABBEAgASADKAIEEQEACwwECwUgBCAAQbABaiAAQYABaiIBIAFBKGogAhCxAiABa0ECdWotAAA6AAAgBEEBaiEEIAJBBGohAgwBCwsQRgALEEYACyAAQewEaiAAQegEahBCBEAgBSAFKAIAQQJyNgIACyAAKALsBCEKIAAoAsABIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAHKAIAIQEgB0EANgIAIAEEQCABIAcoAgQRAQALIABB8ARqJAAgCgu0AQEEfyMAQRBrIgQkACAEIAE2AgwgAigCACIFQfD///8HSQRAAkAgBUEKTQRAIAQgBToACyAEIQEMAQsgBUEPckEBaiIGEDIhASAEIAZBgICAgHhyNgIIIAQgATYCACAEIAU2AgQLIAEgAkEEaiAF/AoAACABIAVqQQA6AAAgBEEMaiAEIAMgABEDACEHIAQsAAtBAEgEQCAEKAIAEC8LIAQoAgwQBCAEQRBqJAAgBw8LEE0AC94GAQZ/IwBBkAFrIgAkACAAIAI2AogBIAAgATYCjAEgAEH3ATYCFCAAQRhqIABBIGogAEEUaiIIEFEhCSAAQRBqIgcgBCgCHCIBNgIAIAFBBGpBAf4eAgAaIAcQciEBIABBADoADyAAQYwBaiACIAMgByAEKAIEIAUgAEEPaiABIAkgCCAAQYQBahDDAwRAIwBBEGsiAiQAAkAgBi0AC0EHdgRAIAYoAgAhCiACQQA6AA8gCiACLQAPOgAAIAZBADYCBAwBCyACQQA6AA4gBiACLQAOOgAAIAYgBi0AC0GAAXE6AAsgBiAGLQALQf8AcToACwsgAkEQaiQAIAAtAA8EQCAGIAFBLSABKAIAKAIcEQQAEKICCyABQTAgASgCACgCHBEEACELIAkoAgAhAiAAKAIUIgdBAWshAyALQf8BcSEBA0ACQCACIANPDQAgAi0AACABRw0AIAJBAWohAgwBCwsjAEEQayIBJAACfyAGLQALQQd2BEAgBigCBAwBCyAGLQALQf8AcQshAyAGLQALQQd2BH8gBigCCEH/////B3FBAWsFQQoLIQQCQCAHIAJrIghFDQACfyAGLQALQQd2BEAgBigCAAwBCyAGCyACTQR/An8gBi0AC0EHdgRAIAYoAgAMAQsgBgsCfyAGLQALQQd2BEAgBigCBAwBCyAGLQALQf8AcQtqIAJPBUEAC0UEQCAIIAQgA2tLBEAgBiAEIAMgBGsgCGogAyADEKUCCwJ/IAYtAAtBB3YEQCAGKAIADAELIAYLIANqIQQDQCACIAdHBEAgBCACLQAAOgAAIAJBAWohAiAEQQFqIQQMAQsLIAFBADoADyAEIAEtAA86AAAgBiADIAhqEJkBDAELIwBBEGsiAyQAIAEgAiAHEPkDIANBEGokACAGAn8gAS0AC0EHdgRAIAEoAgAMAQsgAQsCfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQsQXxogARAzGgsgAUEQaiQACyAAQYwBaiAAQYgBahBDBEAgBSAFKAIAQQJyNgIACyAAKAKMASEMIAAoAhAiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAkoAgAhASAJQQA2AgAgAQRAIAEgCSgCBBEBAAsgAEGQAWokACAMC8YEAQR/IwBBkAJrIgAkACAAIAI2AogCIAAgATYCjAIgAEH3ATYCECAAQZgBaiAAQaABaiAAQRBqIgEQUSEHIABBkAFqIgkgBCgCHCIINgIAIAhBBGpBAf4eAgAaIAkQciEIIABBADoAjwECQCAAQYwCaiACIAMgCSAEKAIEIAUgAEGPAWogCCAHIABBlAFqIABBhAJqEMMDRQ0AIABBnzkoAAA2AIcBIABBmDkpAAA3A4ABIAggAEGAAWogAEGKAWogAEH2AGogCCgCACgCIBEIABogAEH2ATYCECAAQQhqQQAgARBRIQMgASEEAkAgACgClAEgBygCAGsiAUHjAE4EQCABQQJqEDshAiADKAIAIQEgAyACNgIAIAEEQCABIAMoAgQRAQALIAMoAgAiBEUNAQsgAC0AjwEEQCAEQS06AAAgBEEBaiEECyAHKAIAIQIDQCAAKAKUASACTQRAAkAgBEEAOgAAIAAgBjYCACAAQRBqIAAQ5ANBAUcNACADKAIAIQEgA0EANgIAIAEEQCABIAMoAgQRAQALDAQLBSAEIABB9gBqIgEgAUEKaiACELQCIABrIABqLQAKOgAAIARBAWohBCACQQFqIQIMAQsLEEYACxBGAAsgAEGMAmogAEGIAmoQQwRAIAUgBSgCAEECcjYCAAsgACgCjAIhCiAAKAKQASIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgBygCACEBIAdBADYCACABBEAgASAHKAIEEQEACyAAQZACaiQAIAoLoQMBBH8jAEGgA2siByQAIAcgB0GgA2oiAzYCDCMAQZABayICJAAgAiACQYQBajYCHCAAQQhqIAJBIGoiCCACQRxqIAQgBSAGEMcDIAJCADcDECACIAg2AgwgBygCDCAHQRBqIgRrQQJ1IQUgACgCCCEGIwBBEGsiACQAIAAgBjYCDCAAQQhqIABBDGoQfyEJIAQgAkEMaiAFIAJBEGoQ4gMhBSAJEH4gAEEQaiQAIAVBf0YEQBBGAAsgByAEIAVBAnRqNgIMIAJBkAFqJAAgBygCDCECIwBBEGsiBiQAIwBBIGsiACQAIABBGGogBCACEL0CIAAoAhghBSAAKAIcIQcjAEEQayICJAAgAiAFNgIIIAIgATYCDANAIAUgB0cEQCACQQxqIAUoAgAQ+gMgAiAFQQRqIgU2AggMAQsLIAAgAigCCDYCECAAIAIoAgw2AhQgAkEQaiQAIAAgBCAAKAIQIARrajYCDCAAIAAoAhQ2AgggBiAAKAIMNgIIIAYgACgCCDYCDCAAQSBqJAAgBigCDCEKIAZBEGokACADJAAgCguLAgECfyMAQYABayICJAAgAiACQfQAajYCDCAAQQhqIAJBEGoiAyACQQxqIAQgBSAGEMcDIAIoAgwhBCMAQRBrIgYkACMAQSBrIgAkACAAQRhqIAMgBBC9AiAAKAIYIQUgACgCHCEHIwBBEGsiBCQAIAQgBTYCCCAEIAE2AgwDQCAFIAdHBEAgBEEMaiAFLAAAEPwDIAQgBUEBaiIFNgIIDAELCyAAIAQoAgg2AhAgACAEKAIMNgIUIARBEGokACAAIAMgACgCECADa2o2AgwgACAAKAIUNgIIIAYgACgCDDYCCCAGIAAoAgg2AgwgAEEgaiQAIAYoAgwhCCAGQRBqJAAgAkGAAWokACAIC9gPAQN/IwBBMGsiByQAIAcgATYCLCAEQQA2AgAgByADKAIcIgg2AgAgCEEEakEB/h4CABogBxBsIQggBygCACIJQQRqQX/+HgIARQRAIAkgCSgCACgCCBEBAAsCfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgBkHBAGsOOQABFwQXBRcGBxcXFwoXFxcXDg8QFxcXExUXFxcXFxcXAAECAwMXFwEXCBcXCQsXDBcNFwsXFxESFBYLIAAgBUEYaiAHQSxqIAIgBCAIEMoDDBgLIAAgBUEQaiAHQSxqIAIgBCAIEMkDDBcLIAcgACABIAIgAyAEIAUCfyAAQQhqIAAoAggoAgwRAAAiAC0AC0EHdgRAIAAoAgAMAQsgAAsCfyAALQALQQd2BEAgACgCAAwBCyAACwJ/IAAtAAtBB3YEQCAAKAIEDAELIAAtAAtB/wBxC0ECdGoQkgE2AiwMFgsgB0EsaiACIAQgCEECEIkBIQAgBCgCACEBAkACQCAAQQFrQR5LDQAgAUEEcQ0AIAUgADYCDAwBCyAEIAFBBHI2AgALDBULIAdBqOsCKQMANwMYIAdBoOsCKQMANwMQIAdBmOsCKQMANwMIIAdBkOsCKQMANwMAIAcgACABIAIgAyAEIAUgByAHQSBqEJIBNgIsDBQLIAdByOsCKQMANwMYIAdBwOsCKQMANwMQIAdBuOsCKQMANwMIIAdBsOsCKQMANwMAIAcgACABIAIgAyAEIAUgByAHQSBqEJIBNgIsDBMLIAdBLGogAiAEIAhBAhCJASEAIAQoAgAhAQJAAkAgAEEXSg0AIAFBBHENACAFIAA2AggMAQsgBCABQQRyNgIACwwSCyAHQSxqIAIgBCAIQQIQiQEhACAEKAIAIQECQAJAIABBAWtBC0sNACABQQRxDQAgBSAANgIIDAELIAQgAUEEcjYCAAsMEQsgB0EsaiACIAQgCEEDEIkBIQAgBCgCACEBAkACQCAAQe0CSg0AIAFBBHENACAFIAA2AhwMAQsgBCABQQRyNgIACwwQCyAHQSxqIAIgBCAIQQIQiQEhASAEKAIAIQACQAJAIAFBAWsiAUELSw0AIABBBHENACAFIAE2AhAMAQsgBCAAQQRyNgIACwwPCyAHQSxqIAIgBCAIQQIQiQEhACAEKAIAIQECQAJAIABBO0oNACABQQRxDQAgBSAANgIEDAELIAQgAUEEcjYCAAsMDgsgB0EsaiEAIwBBEGsiASQAIAEgAjYCDANAAkAgACABQQxqEEINACAIQQECfyAAKAIAIgIoAgwiAyACKAIQRgRAIAIgAigCACgCJBEAAAwBCyADKAIACyAIKAIAKAIMEQMARQ0AIAAQXBoMAQsLIAAgAUEMahBCBEAgBCAEKAIAQQJyNgIACyABQRBqJAAMDQsgB0EsaiEBAkACfyAAQQhqIAAoAggoAggRAAAiAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELQQACfyAALQAXQQd2BEAgACgCEAwBCyAALQAXQf8AcQtrRgRAIAQgBCgCAEEEcjYCAAwBCyABIAIgACAAQRhqIAggBEEAEO4BIQIgBSgCCCEBAkAgACACRw0AIAFBDEcNACAFQQA2AggMAQsCQCACIABrQQxHDQAgAUELSg0AIAUgAUEMajYCCAsLDAwLIAdB0OsCQSz8CgAAIAcgACABIAIgAyAEIAUgByAHQSxqEJIBNgIsDAsLIAdBkOwCKAIANgIQIAdBiOwCKQMANwMIIAdBgOwCKQMANwMAIAcgACABIAIgAyAEIAUgByAHQRRqEJIBNgIsDAoLIAdBLGogAiAEIAhBAhCJASEAIAQoAgAhAQJAAkAgAEE8Sg0AIAFBBHENACAFIAA2AgAMAQsgBCABQQRyNgIACwwJCyAHQbjsAikDADcDGCAHQbDsAikDADcDECAHQajsAikDADcDCCAHQaDsAikDADcDACAHIAAgASACIAMgBCAFIAcgB0EgahCSATYCLAwICyAHQSxqIAIgBCAIQQEQiQEhACAEKAIAIQECQAJAIABBBkoNACABQQRxDQAgBSAANgIYDAELIAQgAUEEcjYCAAsMBwsgACABIAIgAyAEIAUgACgCACgCFBEHAAwHCyAHIAAgASACIAMgBCAFAn8gAEEIaiAAKAIIKAIYEQAAIgAtAAtBB3YEQCAAKAIADAELIAALAn8gAC0AC0EHdgRAIAAoAgAMAQsgAAsCfyAALQALQQd2BEAgACgCBAwBCyAALQALQf8AcQtBAnRqEJIBNgIsDAULIAVBFGogB0EsaiACIAQgCBDIAwwECyAHQSxqIAIgBCAIQQQQiQEhACAELQAAQQRxRQRAIAUgAEHsDms2AhQLDAMLIAZBJUYNAQsgBCAEKAIAQQRyNgIADAELIwBBEGsiACQAIAAgAjYCDEEGIQECQAJAIAdBLGoiAyAAQQxqIgUQQg0AQQQhASAIAn8gAygCACICKAIMIgYgAigCEEYEQCACIAIoAgAoAiQRAAAMAQsgBigCAAtBACAIKAIAKAI0EQMAQSVHDQBBAiEBIAMQXCAFEEJFDQELIAQgBCgCACABcjYCAAsgAEEQaiQACyAHKAIsCyEKIAdBMGokACAKC3sBAX8jAEEQayIAJAAgACABNgIMIABBCGoiASADKAIcIgM2AgAgA0EEakEB/h4CABogARBsIQMgASgCACIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgBUEUaiAAQQxqIAIgBCADEMgDIAAoAgwhBiAAQRBqJAAgBgt9AQJ/IwBBEGsiBiQAIAYgATYCDCAGQQhqIgEgAygCHCIDNgIAIANBBGpBAf4eAgAaIAEQbCEDIAEoAgAiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAAgBUEQaiAGQQxqIAIgBCADEMkDIAYoAgwhByAGQRBqJAAgBwt9AQJ/IwBBEGsiBiQAIAYgATYCDCAGQQhqIgEgAygCHCIDNgIAIANBBGpBAf4eAgAaIAEQbCEDIAEoAgAiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAAgBUEYaiAGQQxqIAIgBCADEMoDIAYoAgwhByAGQRBqJAAgBwtxACAAIAEgAiADIAQgBQJ/IABBCGogACgCCCgCFBEAACIALQALQQd2BEAgACgCAAwBCyAACwJ/IAAtAAtBB3YEQCAAKAIADAELIAALAn8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELQQJ0ahCSAQtdAQJ/IwBBIGsiBiQAIAZBuOwCKQMANwMYIAZBsOwCKQMANwMQIAZBqOwCKQMANwMIIAZBoOwCKQMANwMAIAAgASACIAMgBCAFIAYgBkEgaiIBEJIBIQcgASQAIAcLhQ8BA38jAEEQayIHJAAgByABNgIMIARBADYCACAHIAMoAhwiCDYCACAIQQRqQQH+HgIAGiAHEHIhCCAHKAIAIglBBGpBf/4eAgBFBEAgCSAJKAIAKAIIEQEACwJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAGQcEAaw45AAEXBBcFFwYHFxcXChcXFxcODxAXFxcTFRcXFxcXFxcAAQIDAxcXARcIFxcJCxcMFw0XCxcXERIUFgsgACAFQRhqIAdBDGogAiAEIAgQzQMMGAsgACAFQRBqIAdBDGogAiAEIAgQzAMMFwsgByAAIAEgAiADIAQgBQJ/IABBCGogACgCCCgCDBEAACIALQALQQd2BEAgACgCAAwBCyAACwJ/IAAtAAtBB3YEQCAAKAIADAELIAALAn8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELahCTATYCDAwWCyAHQQxqIAIgBCAIQQIQigEhACAEKAIAIQECQAJAIABBAWtBHksNACABQQRxDQAgBSAANgIMDAELIAQgAUEEcjYCAAsMFQsgB0Kl2r2pwuzLkvkANwMAIAcgACABIAIgAyAEIAUgByAHQQhqEJMBNgIMDBQLIAdCpbK1qdKty5LkADcDACAHIAAgASACIAMgBCAFIAcgB0EIahCTATYCDAwTCyAHQQxqIAIgBCAIQQIQigEhACAEKAIAIQECQAJAIABBF0oNACABQQRxDQAgBSAANgIIDAELIAQgAUEEcjYCAAsMEgsgB0EMaiACIAQgCEECEIoBIQAgBCgCACEBAkACQCAAQQFrQQtLDQAgAUEEcQ0AIAUgADYCCAwBCyAEIAFBBHI2AgALDBELIAdBDGogAiAEIAhBAxCKASEAIAQoAgAhAQJAAkAgAEHtAkoNACABQQRxDQAgBSAANgIcDAELIAQgAUEEcjYCAAsMEAsgB0EMaiACIAQgCEECEIoBIQEgBCgCACEAAkACQCABQQFrIgFBC0sNACAAQQRxDQAgBSABNgIQDAELIAQgAEEEcjYCAAsMDwsgB0EMaiACIAQgCEECEIoBIQAgBCgCACEBAkACQCAAQTtKDQAgAUEEcQ0AIAUgADYCBAwBCyAEIAFBBHI2AgALDA4LIAdBDGohACMAQRBrIgEkACABIAI2AgwDQAJAIAAgAUEMahBDDQACfyAAKAIAIgIoAgwiAyACKAIQRgRAIAIgAigCACgCJBEAAAwBCyADLQAAC8AiAkEATgR/IAgoAgggAkH/AXFBAnRqKAIAQQFxBUEAC0UNACAAEF0aDAELCyAAIAFBDGoQQwRAIAQgBCgCAEECcjYCAAsgAUEQaiQADA0LIAdBDGohAQJAAn8gAEEIaiAAKAIIKAIIEQAAIgAtAAtBB3YEQCAAKAIEDAELIAAtAAtB/wBxC0EAAn8gAC0AF0EHdgRAIAAoAhAMAQsgAC0AF0H/AHELa0YEQCAEIAQoAgBBBHI2AgAMAQsgASACIAAgAEEYaiAIIARBABDvASECIAUoAgghAQJAIAAgAkcNACABQQxHDQAgBUEANgIIDAELAkAgAiAAa0EMRw0AIAFBC0oNACAFIAFBDGo2AggLCwwMCyAHQfjqAigAADYAByAHQfHqAikAADcDACAHIAAgASACIAMgBCAFIAcgB0ELahCTATYCDAwLCyAHQYDrAi0AADoABCAHQfzqAigAADYCACAHIAAgASACIAMgBCAFIAcgB0EFahCTATYCDAwKCyAHQQxqIAIgBCAIQQIQigEhACAEKAIAIQECQAJAIABBPEoNACABQQRxDQAgBSAANgIADAELIAQgAUEEcjYCAAsMCQsgB0KlkOmp0snOktMANwMAIAcgACABIAIgAyAEIAUgByAHQQhqEJMBNgIMDAgLIAdBDGogAiAEIAhBARCKASEAIAQoAgAhAQJAAkAgAEEGSg0AIAFBBHENACAFIAA2AhgMAQsgBCABQQRyNgIACwwHCyAAIAEgAiADIAQgBSAAKAIAKAIUEQcADAcLIAcgACABIAIgAyAEIAUCfyAAQQhqIAAoAggoAhgRAAAiAC0AC0EHdgRAIAAoAgAMAQsgAAsCfyAALQALQQd2BEAgACgCAAwBCyAACwJ/IAAtAAtBB3YEQCAAKAIEDAELIAAtAAtB/wBxC2oQkwE2AgwMBQsgBUEUaiAHQQxqIAIgBCAIEMsDDAQLIAdBDGogAiAEIAhBBBCKASEAIAQtAABBBHFFBEAgBSAAQewOazYCFAsMAwsgBkElRg0BCyAEIAQoAgBBBHI2AgAMAQsjAEEQayIAJAAgACACNgIMQQYhAQJAAkAgB0EMaiIDIABBDGoiBRBDDQBBBCEBIAgCfyADKAIAIgIoAgwiBiACKAIQRgRAIAIgAigCACgCJBEAAAwBCyAGLQAAC8BBACAIKAIAKAIkEQMAQSVHDQBBAiEBIAMQXSAFEENFDQELIAQgBCgCACABcjYCAAsgAEEQaiQACyAHKAIMCyEKIAdBEGokACAKC3sBAX8jAEEQayIAJAAgACABNgIMIABBCGoiASADKAIcIgM2AgAgA0EEakEB/h4CABogARByIQMgASgCACIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgBUEUaiAAQQxqIAIgBCADEMsDIAAoAgwhBiAAQRBqJAAgBgt9AQJ/IwBBEGsiBiQAIAYgATYCDCAGQQhqIgEgAygCHCIDNgIAIANBBGpBAf4eAgAaIAEQciEDIAEoAgAiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAAgBUEQaiAGQQxqIAIgBCADEMwDIAYoAgwhByAGQRBqJAAgBwt9AQJ/IwBBEGsiBiQAIAYgATYCDCAGQQhqIgEgAygCHCIDNgIAIANBBGpBAf4eAgAaIAEQciEDIAEoAgAiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIAAgBUEYaiAGQQxqIAIgBCADEM0DIAYoAgwhByAGQRBqJAAgBwtuACAAIAEgAiADIAQgBQJ/IABBCGogACgCCCgCFBEAACIALQALQQd2BEAgACgCAAwBCyAACwJ/IAAtAAtBB3YEQCAAKAIADAELIAALAn8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELahCTAQtAAQJ/IwBBEGsiBiQAIAZCpZDpqdLJzpLTADcDCCAAIAEgAiADIAQgBSAGQQhqIAZBEGoiARCTASEHIAEkACAHC8sBAQd/IwBB0AFrIgAkABBEIQUgACAENgIAIABBsAFqIgcgByAHQRQgBUH5FSAAEGMiCmoiBSACEHQhCCAAQRBqIgQgAigCHCIGNgIAIAZBBGpBAf4eAgAaIAQQbCEGIAQoAgAiCUEEakF//h4CAEUEQCAJIAkoAgAoAggRAQALIAYgByAFIAQgBigCACgCMBEIABogASAEIApBAnQgBGoiASAIIABrQQJ0IABqQbAFayAFIAhGGyABIAIgAxCUASELIABB0AFqJAAgCwuSBQEJfwJ/IwBBoANrIgYkACAGQiU3A5gDIAZBmANqIgdBAXJB0zAgAigCBBDsASEIIAYgBkHwAmoiCTYC7AIQRCEAAn8gCARAIAIoAgghCiAGQUBrIAU3AwAgBiAENwM4IAYgCjYCMCAJQR4gACAHIAZBMGoQYwwBCyAGIAQ3A1AgBiAFNwNYIAZB8AJqQR4gACAGQZgDaiAGQdAAahBjCyEAIAZB9gE2AoABIAZB5AJqQQAgBkGAAWoQUSEJIAZB8AJqIgohBwJAIABBHk4EQBBEIQACfyAIBEAgAigCCCEHIAYgBTcDECAGIAQ3AwggBiAHNgIAIAZB7AJqIAAgBkGYA2ogBhCLAQwBCyAGIAQ3AyAgBiAFNwMoIAZB7AJqIAAgBkGYA2ogBkEgahCLAQsiAEF/Rg0BIAkoAgAhByAJIAYoAuwCNgIAIAcEQCAHIAkoAgQRAQALIAYoAuwCIQcLIAcgACAHaiILIAIQdCEMIAZB9gE2AoABIAZB+ABqQQAgBkGAAWoiBxBRIQgCQCAGKALsAiAGQfACakYEQCAHIQAMAQsgAEEDdBA7IgBFDQEgCCgCACEHIAggADYCACAHBEAgByAIKAIEEQEACyAGKALsAiEKCyAGQewAaiIHIAIoAhwiDTYCACANQQRqQQH+HgIAGiAKIAwgCyAAIAZB9ABqIAZB8ABqIAcQ0AMgBygCACIHQQRqQX/+HgIARQRAIAcgBygCACgCCBEBAAsgASAAIAYoAnQgBigCcCACIAMQlAEhDiAIKAIAIQAgCEEANgIAIAAEQCAAIAgoAgQRAQALIAkoAgAhACAJQQA2AgAgAARAIAAgCSgCBBEBAAsgBkGgA2okACAODAELEEYACwvvBAEJfwJ/IwBB8AJrIgUkACAFQiU3A+gCIAVB6AJqIgZBAXJB4fkAIAIoAgQQ7AEhByAFIAVBwAJqIgg2ArwCEEQhAAJ/IAcEQCACKAIIIQkgBSAEOQMoIAUgCTYCICAIQR4gACAGIAVBIGoQYwwBCyAFIAQ5AzAgBUHAAmpBHiAAIAVB6AJqIAVBMGoQYwshACAFQfYBNgJQIAVBtAJqQQAgBUHQAGoQUSEIIAVBwAJqIgkhBgJAIABBHk4EQBBEIQACfyAHBEAgAigCCCEGIAUgBDkDCCAFIAY2AgAgBUG8AmogACAFQegCaiAFEIsBDAELIAUgBDkDECAFQbwCaiAAIAVB6AJqIAVBEGoQiwELIgBBf0YNASAIKAIAIQYgCCAFKAK8AjYCACAGBEAgBiAIKAIEEQEACyAFKAK8AiEGCyAGIAAgBmoiCiACEHQhCyAFQfYBNgJQIAVByABqQQAgBUHQAGoiBhBRIQcCQCAFKAK8AiAFQcACakYEQCAGIQAMAQsgAEEDdBA7IgBFDQEgBygCACEGIAcgADYCACAGBEAgBiAHKAIEEQEACyAFKAK8AiEJCyAFQTxqIgYgAigCHCIMNgIAIAxBBGpBAf4eAgAaIAkgCyAKIAAgBUHEAGogBUFAayAGENADIAYoAgAiBkEEakF//h4CAEUEQCAGIAYoAgAoAggRAQALIAEgACAFKAJEIAUoAkAgAiADEJQBIQ0gBygCACEAIAdBADYCACAABEAgACAHKAIEEQEACyAIKAIAIQAgCEEANgIAIAAEQCAAIAgoAgQRAQALIAVB8AJqJAAgDQwBCxBGAAsL0wEBBn8jAEGAAmsiACQAIABCJTcD+AEgAEH4AWoiB0EBckGnGkEAIAIoAgQQnAEQRCEGIAAgBDcDACAAQeABaiIFIAVBGCAGIAcgABBjIAVqIgYgAhB0IQggAEEUaiIHIAIoAhwiCTYCACAJQQRqQQH+HgIAGiAFIAggBiAAQSBqIgYgAEEcaiAAQRhqIAcQ6wEgBygCACIFQQRqQX/+HgIARQRAIAUgBSgCACgCCBEBAAsgASAGIAAoAhwgACgCGCACIAMQlAEhCiAAQYACaiQAIAoL0wEBBX8jAEGQAWsiACQAIABCJTcDiAEgAEGIAWoiBkEBckHEGkEAIAIoAgQQnAEQRCEFIAAgBDYCACAAQfsAaiIEIARBDSAFIAYgABBjIARqIgUgAhB0IQcgAEEEaiIGIAIoAhwiCDYCACAIQQRqQQH+HgIAGiAEIAcgBSAAQRBqIgUgAEEMaiAAQQhqIAYQ6wEgBigCACIEQQRqQX/+HgIARQRAIAQgBCgCACgCCBEBAAsgASAFIAAoAgwgACgCCCACIAMQlAEhCSAAQZABaiQAIAkL0wEBBn8jAEGAAmsiACQAIABCJTcD+AEgAEH4AWoiB0EBckGnGkEBIAIoAgQQnAEQRCEGIAAgBDcDACAAQeABaiIFIAVBGCAGIAcgABBjIAVqIgYgAhB0IQggAEEUaiIHIAIoAhwiCTYCACAJQQRqQQH+HgIAGiAFIAggBiAAQSBqIgYgAEEcaiAAQRhqIAcQ6wEgBygCACIFQQRqQX/+HgIARQRAIAUgBSgCACgCCBEBAAsgASAGIAAoAhwgACgCGCACIAMQlAEhCiAAQYACaiQAIAoL0wEBBX8jAEGQAWsiACQAIABCJTcDiAEgAEGIAWoiBkEBckHEGkEBIAIoAgQQnAEQRCEFIAAgBDYCACAAQfsAaiIEIARBDSAFIAYgABBjIARqIgUgAhB0IQcgAEEEaiIGIAIoAhwiCDYCACAIQQRqQQH+HgIAGiAEIAcgBSAAQRBqIgUgAEEMaiAAQQhqIAYQ6wEgBigCACIEQQRqQX/+HgIARQRAIAQgBCgCACgCCBEBAAsgASAFIAAoAgwgACgCCCACIAMQlAEhCSAAQZABaiQAIAkLjAIBAX8jAEEgayIFJAAgBSABNgIcAkAgAigCBEEBcUUEQCAAIAEgAiADIAQgACgCACgCGBEKACECDAELIAVBEGoiASACKAIcIgA2AgAgAEEEakEB/h4CABogARC/ASEAIAEoAgAiAkEEakF//h4CAEUEQCACIAIoAgAoAggRAQALAkAgBARAIAEgACAAKAIAKAIYEQIADAELIAVBEGogACAAKAIAKAIcEQIACyAFIAVBEGoQdTYCDANAIAUgBUEQaiIAEJsBNgIIIAUoAgwiASAFKAIIRwRAIAVBHGogASgCABD6AyAFIAUoAgxBBGo2AgwMAQUgBSgCHCECIAAQUBoLCwsgBUEgaiQAIAILwwEBB38jAEHgAGsiACQAEEQhBSAAIAQ2AgAgAEFAayIHIAcgB0EUIAVB+RUgABBjIgpqIgUgAhB0IQggAEEQaiIEIAIoAhwiBjYCACAGQQRqQQH+HgIAGiAEEHIhBiAEKAIAIglBBGpBf/4eAgBFBEAgCSAJKAIAKAIIEQEACyAGIAcgBSAEIAYoAgAoAiARCAAaIAEgBCAEIApqIgEgCCAAayAAakEwayAFIAhGGyABIAIgAxCVASELIABB4ABqJAAgCwuSBQEJfwJ/IwBBgAJrIgYkACAGQiU3A/gBIAZB+AFqIgdBAXJB0zAgAigCBBDsASEIIAYgBkHQAWoiCTYCzAEQRCEAAn8gCARAIAIoAgghCiAGQUBrIAU3AwAgBiAENwM4IAYgCjYCMCAJQR4gACAHIAZBMGoQYwwBCyAGIAQ3A1AgBiAFNwNYIAZB0AFqQR4gACAGQfgBaiAGQdAAahBjCyEAIAZB9gE2AoABIAZBxAFqQQAgBkGAAWoQUSEJIAZB0AFqIgohBwJAIABBHk4EQBBEIQACfyAIBEAgAigCCCEHIAYgBTcDECAGIAQ3AwggBiAHNgIAIAZBzAFqIAAgBkH4AWogBhCLAQwBCyAGIAQ3AyAgBiAFNwMoIAZBzAFqIAAgBkH4AWogBkEgahCLAQsiAEF/Rg0BIAkoAgAhByAJIAYoAswBNgIAIAcEQCAHIAkoAgQRAQALIAYoAswBIQcLIAcgACAHaiILIAIQdCEMIAZB9gE2AoABIAZB+ABqQQAgBkGAAWoiBxBRIQgCQCAGKALMASAGQdABakYEQCAHIQAMAQsgAEEBdBA7IgBFDQEgCCgCACEHIAggADYCACAHBEAgByAIKAIEEQEACyAGKALMASEKCyAGQewAaiIHIAIoAhwiDTYCACANQQRqQQH+HgIAGiAKIAwgCyAAIAZB9ABqIAZB8ABqIAcQ0gMgBygCACIHQQRqQX/+HgIARQRAIAcgBygCACgCCBEBAAsgASAAIAYoAnQgBigCcCACIAMQlQEhDiAIKAIAIQAgCEEANgIAIAAEQCAAIAgoAgQRAQALIAkoAgAhACAJQQA2AgAgAARAIAAgCSgCBBEBAAsgBkGAAmokACAODAELEEYACwvvBAEJfwJ/IwBB0AFrIgUkACAFQiU3A8gBIAVByAFqIgZBAXJB4fkAIAIoAgQQ7AEhByAFIAVBoAFqIgg2ApwBEEQhAAJ/IAcEQCACKAIIIQkgBSAEOQMoIAUgCTYCICAIQR4gACAGIAVBIGoQYwwBCyAFIAQ5AzAgBUGgAWpBHiAAIAVByAFqIAVBMGoQYwshACAFQfYBNgJQIAVBlAFqQQAgBUHQAGoQUSEIIAVBoAFqIgkhBgJAIABBHk4EQBBEIQACfyAHBEAgAigCCCEGIAUgBDkDCCAFIAY2AgAgBUGcAWogACAFQcgBaiAFEIsBDAELIAUgBDkDECAFQZwBaiAAIAVByAFqIAVBEGoQiwELIgBBf0YNASAIKAIAIQYgCCAFKAKcATYCACAGBEAgBiAIKAIEEQEACyAFKAKcASEGCyAGIAAgBmoiCiACEHQhCyAFQfYBNgJQIAVByABqQQAgBUHQAGoiBhBRIQcCQCAFKAKcASAFQaABakYEQCAGIQAMAQsgAEEBdBA7IgBFDQEgBygCACEGIAcgADYCACAGBEAgBiAHKAIEEQEACyAFKAKcASEJCyAFQTxqIgYgAigCHCIMNgIAIAxBBGpBAf4eAgAaIAkgCyAKIAAgBUHEAGogBUFAayAGENIDIAYoAgAiBkEEakF//h4CAEUEQCAGIAYoAgAoAggRAQALIAEgACAFKAJEIAUoAkAgAiADEJUBIQ0gBygCACEAIAdBADYCACAABEAgACAHKAIEEQEACyAIKAIAIQAgCEEANgIAIAAEQCAAIAgoAgQRAQALIAVB0AFqJAAgDQwBCxBGAAsL0gEBBn8jAEHwAGsiACQAIABCJTcDaCAAQegAaiIHQQFyQacaQQAgAigCBBCcARBEIQYgACAENwMAIABB0ABqIgUgBUEYIAYgByAAEGMgBWoiBiACEHQhCCAAQRRqIgcgAigCHCIJNgIAIAlBBGpBAf4eAgAaIAUgCCAGIABBIGoiBiAAQRxqIABBGGogBxDtASAHKAIAIgVBBGpBf/4eAgBFBEAgBSAFKAIAKAIIEQEACyABIAYgACgCHCAAKAIYIAIgAxCVASEKIABB8ABqJAAgCgvOAQEFfyMAQUBqIgAkACAAQiU3AzggAEE4aiIGQQFyQcQaQQAgAigCBBCcARBEIQUgACAENgIAIABBK2oiBCAEQQ0gBSAGIAAQYyAEaiIFIAIQdCEHIABBBGoiBiACKAIcIgg2AgAgCEEEakEB/h4CABogBCAHIAUgAEEQaiIFIABBDGogAEEIaiAGEO0BIAYoAgAiBEEEakF//h4CAEUEQCAEIAQoAgAoAggRAQALIAEgBSAAKAIMIAAoAgggAiADEJUBIQkgAEFAayQAIAkL0gEBBn8jAEHwAGsiACQAIABCJTcDaCAAQegAaiIHQQFyQacaQQEgAigCBBCcARBEIQYgACAENwMAIABB0ABqIgUgBUEYIAYgByAAEGMgBWoiBiACEHQhCCAAQRRqIgcgAigCHCIJNgIAIAlBBGpBAf4eAgAaIAUgCCAGIABBIGoiBiAAQRxqIABBGGogBxDtASAHKAIAIgVBBGpBf/4eAgBFBEAgBSAFKAIAKAIIEQEACyABIAYgACgCHCAAKAIYIAIgAxCVASEKIABB8ABqJAAgCgvOAQEFfyMAQUBqIgAkACAAQiU3AzggAEE4aiIGQQFyQcQaQQEgAigCBBCcARBEIQUgACAENgIAIABBK2oiBCAEQQ0gBSAGIAAQYyAEaiIFIAIQdCEHIABBBGoiBiACKAIcIgg2AgAgCEEEakEB/h4CABogBCAHIAUgAEEQaiIFIABBDGogAEEIaiAGEO0BIAYoAgAiBEEEakF//h4CAEUEQCAEIAQoAgAoAggRAQALIAEgBSAAKAIMIAAoAgggAiADEJUBIQkgAEFAayQAIAkLjAIBAX8jAEEgayIFJAAgBSABNgIcAkAgAigCBEEBcUUEQCAAIAEgAiADIAQgACgCACgCGBEKACECDAELIAVBEGoiASACKAIcIgA2AgAgAEEEakEB/h4CABogARDBASEAIAEoAgAiAkEEakF//h4CAEUEQCACIAIoAgAoAggRAQALAkAgBARAIAEgACAAKAIAKAIYEQIADAELIAVBEGogACAAKAIAKAIcEQIACyAFIAVBEGoQdTYCDANAIAUgBUEQaiIAEJ0BNgIIIAUoAgwiASAFKAIIRwRAIAVBHGogASwAABD8AyAFIAUoAgxBAWo2AgwMAQUgBSgCHCECIAAQMxoLCwsgBUEgaiQAIAILwQUBBn8jAEHAAmsiACQAIAAgAjYCuAIgACABNgK8AiMAQRBrIgIkACAAQcQBaiIBQgA3AgAgAUEANgIIIAJBEGokACAAQRBqIgYgAygCHCICNgIAIAJBBGpBAf4eAgAaIAYQbCICQdDqAkHq6gIgAEHQAWogAigCACgCMBEIABogBigCACICQQRqQX/+HgIARQRAIAIgAigCACgCCBEBAAsgASEDIwBBEGsiASQAIABBuAFqIgJCADcCACACQQA2AgggAUEQaiQAIAIgAi0AC0EHdgR/IAIoAghB/////wdxQQFrBUEKCxA6IAACfyACLQALQQd2BEAgAigCAAwBCyACCyIBNgK0ASAAIAY2AgwgAEEANgIIA0ACQCAAQbwCaiAAQbgCahBCDQAgACgCtAECfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQsgAWpGBEACfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQshBiACAn8gAi0AC0EHdgRAIAIoAgQMAQsgAi0AC0H/AHELQQF0EDogAiACLQALQQd2BH8gAigCCEH/////B3FBAWsFQQoLEDogACAGAn8gAi0AC0EHdgRAIAIoAgAMAQsgAgsiAWo2ArQBCwJ/IABBvAJqIgcoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgoAgALQRAgASAAQbQBaiAAQQhqQQAgAyAAQRBqIABBDGogAEHQAWoQvQENACAHEFwaDAELCyACIAAoArQBIAFrEDoCfyACLQALQQd2BEAgAigCAAwBCyACCyELEEQhCSAAIAU2AgAgCyAJIAAQ1ANBAUcEQCAE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zwFB/wBxC0UNACAAKAIMIgMgAEEQamtBnwFKDQAgACADQQRqNgIMIAMgACgCCDYCAAsgBSACIAAoArQBIAQgBhDYAzcDACAAQcQBaiAAQRBqIAAoAgwgBBBkIABBzAJqIABByAJqEEIEQCAEIAQoAgBBAnI2AgALIAAoAswCIQogARAzGiAAQcQBahAzGiAAQdACaiQAIAoLmgUBBX8jAEHQAmsiACQAIAAgAjYCyAIgACABNgLMAiADEIwBIQYgAyAAQdABahDQASEHIABBxAFqIAMgAEHEAmoQzwEjAEEQayICJAAgAEG4AWoiAUIANwIAIAFBADYCCCACQRBqJAAgASABLQALQQd2BH8gASgCCEH/////B3FBAWsFQQoLEDogAAJ/IAEtAAtBB3YEQCABKAIADAELIAELIgI2ArQBIAAgAEEQajYCDCAAQQA2AggDQAJAIABBzAJqIABByAJqEEINACAAKAK0AQJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyACakYEQAJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyEDIAECfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQtBAXQQOiABIAEtAAtBB3YEfyABKAIIQf////8HcUEBawVBCgsQOiAAIAMCfyABLQALQQd2BEAgASgCAAwBCyABCyICajYCtAELAn8gAEHMAmoiCCgCACIDKAIMIgkgAygCEEYEQCADIAMoAgAoAiQRAAAMAQsgCSgCAAsgBiACIABBtAFqIABBCGogACgCxAIgAEHEAWogAEEQaiAAQQxqIAcQvQENACAIEFwaDAELCwJAAn8gAC0AzwFBB3YEQCAAKALIAQwBCyAALQDPAUH/AHELRQ0AIAAoAgwiAyAAQRBqa0GfAUoNACAAIANBBGo2AgwgAyAAKAIINgIACyAFIAIgACgCtAEgBCAGENsDOwEAIABBxAFqIABBEGogACgCDCAEEGQgAEHMAmogAEHIAmoQQgRAIAQgBCgCAEECcjYCAAsgACgCzAIhCiABEDMaIABBxAFqEDMaIABB0AJqJAAgCguaBQEFfyMAQdACayIAJAAgACACNgLIAiAAIAE2AswCIAMQjAEhBiADIABB0AFqENABIQcgAEHEAWogAyAAQcQCahDPASMAQRBrIgIkACAA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AUEQaiQAIAIgAi0AC0EHdgR/IAIoAghB/////wdxQQFrBUEKCxA6IAACfyACLQALQQd2BEAgAigCAAwBCyACCyIBNgK0ASAAIAY2AgwgAEEANgIIA0ACQCAAQfwBaiAAQfgBahBDDQAgACgCtAECfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQsgAWpGBEACfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQshBiACAn8gAi0AC0EHdgRAIAIoAgQMAQsgAi0AC0H/AHELQQF0EDogAiACLQALQQd2BH8gAigCCEH/////B3FBAWsFQQoLEDogACAGAn8gAi0AC0EHdgRAIAIoAgAMAQsgAgsiAWo2ArQBCwJ/IABB/AFqIgcoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgtAAALwEEQIAEgAEG0AWogAEEIakEAIAMgAEEQaiAAQQxqIABB0AFqEMABDQAgBxBdGgwBCwsgAiAAKAK0ASABaxA6An8gAi0AC0EHdgRAIAIoAgAMAQsgAgshCxBEIQkgACAFNgIAIAsgCSAAENQDQQFHBEAgBEEENgIACyAAQfwBaiAAQfgBahBDBEAgBCAEKAIAQQJyNgIACyAAKAL8ASEKIAIQMxogAxAzGiAAQYACaiQAIAoLHgEBf0HQuwMoAgAiAARAIAAQ4ARB0LsDQQA2AgALC9EFAgN/AX4jAEGQAmsiACQAIAAgAjYCiAIgACABNgKMAiAAQdABaiADIABB4AFqIABB3wFqIABB3gFqELYCIwBBEGsiAiQAIABBxAFqIgFCADcCACABQQA2AgggAkEQaiQAIAEgAS0AC0EHdgR/IAEoAghB/////wdxQQFrBUEKCxA6IAACfyABLQALQQd2BEAgASgCAAwBCyABCyICNgLAASAAIABBIGo2AhwgAEEANgIYIABBAToAFyAAQcUAOgAWA0ACQCAAQYwCaiAAQYgCahBDDQAgACgCwAECfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQsgAmpGBEACfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQshAyABAn8gAS0AC0EHdgRAIAEoAgQMAQsgAS0AC0H/AHELQQF0EDogASABLQALQQd2BH8gASgCCEH/////B3FBAWsFQQoL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QQNxbGogACwADiAxIAV2QQNxbGogACwADyAwIAV2QQNxbGogBiAHai0AAEEPcWwgCmogACwAESAuIAV2QQNxbCAALAAQIC8gBXZBA3FsaiAALAASIC0gBXZBA3FsaiAALAATICwgBXZBA3FsaiAALAAUICsgBXZBA3FsaiAALAAVICogBXZBA3FsaiAALAAWICkgBXZBA3FsaiAALAAXICggBXZBA3FsaiAALAAYICcgBXZBA3FsaiAALAAZICYgBXZBA3FsaiAALAAaICUgBXZBA3FsaiAALAAbICQgBXZBA3FsaiAALAAcICMgBXZBA3FsaiAALAAdICIgBXZBA3FsaiAALAAeICEgBXZBA3FsaiAALAAfICAgBXZBA3FsaiAHIAZBAXJqLQAAQQ9xbGohCiAAQSBqIQAgBUECaiEFIAZBAmohBiAMQQFqIgxBBEcNAAsgBEEgaiEEIAlBCGohCSALIQZBACELIEAhACAGDQALIEEgQiBElCAKspQgQyBClCAOIA8gECARIBIgEyAUIBUgFiAXIBggGSAaIBsgHCAdIB5sampqampqampqampqampqspSTkiFBIAhBAWoiCCANRw0ACwsgASBBOAIAC6YCAQF/IAAgACgCACgCGBEAABogACABEPgDIgE2AkQgAC0AYiECIAAgASABKAIAKAIcEQAAIgE6AGIgASACRwRAIABBADYCECAAQQA2AgwgAEEANgIIIABBADYCHCAAQQA2AhQgAEEANgIYIAAtAGAhASAALQBiBEACQCABRQ0AIAAoAiAiAUUNACABEC8LIAAgAC0AYToAYCAAIAAoAjw2AjQgACgCOCEBIABCADcCOCAAIAE2AiAgAEEAOgBhDwsCQCABDQAgACgCICIBIABBLGpGDQAgAEEAOgBhIAAgATYCOCAAIAAoAjQiATYCPCABEDIhASAAQQE6AGAgACABNgIgDwsgACAAKAI0IgE2AjwgARAyIQEgAEEBOgBhIAAgATYCOAsL8QMCBX8BfiMAQRBrIgMkAAJAIAAoAkBFDQACQCAAKAJEIgQEQCAAKAJcIgJBEHEEQCAAKAIYIAAoAhRHBEBBfyEBIABBfyAAKAIAKAI0EQQAQX9GDQQLIABByABqIQEDQCAAKAJEIgQgASAAKAIgIgIgAiAAKAI0aiADQQxqIAQoAgAoAhQRCgAh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AgAhAAsgAygC1AEgABCkASADIAMoAtgBQQFqNgLYAQsCQCAEQRRqIgAgAUHwA2pGDQAgAS0A+wMiCMAhAiAELAAfQQBOBEAgAkEATgRAIAAgASkD8AM3AgAgACABKAL4AzYCCAwCCyAAIAEoAvADIAEoAvQDEN4BDAELIAAgASgC8AMgAUHwA2ogAkEASCIAGyABKAL0AyAIIAAbEN8BCyAGQQFqIgYgASgCyAQiAEgNAAsLIAMgAygCICICNgLAASACQZiVA0oEQCADIAMoAtwBQQFqNgLcASADIAMoAuABQQFqNgLgASADIAP9AALkASACQZiVA2siBP0R/a4B/QsC5AEgAyADKAL0ASAEajYC9AEgAyADKAL4ASAEajYC+AEgAyADKAL8ASAEajYC/AELAkAgACACTg0AIAFByCU2AuABIAEgAiAAazYC5AFBBEGT4wAgAUHgAWoQNCABKALIBCIGIAMoAiBODQAgA0HUAWohBSADQcQBaiELIAFB8ANqQQRyIQgDQAJAIAMoAvwBIgIgBkgEQCABQZQEaiIAIAYgAmsQOSABIABBsykQOCIAKAIINgKoBCABIAApAgA3A6AEIABCADcCACAAQQA2AgggAUGgBGpBuyoQNyIAKAIAIQIgASAAKAIENgLkAyABIAAoAAc2AOcDIABCADcCACAALQALIQQgAEEANgIIIAEsAPsDQQBIBEAgASgC8AMQLwsgASACNgLwAyAIIAEoAOcDNgADIAggASgC5AM2AgAgASAEOgD7AyABLACrBEEASARAIAEoAqAEEC8LIAEsAJ8EQQBODQEgASgClAQQLwwBCyADKALcASAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQdQpKAAANgADIABB0SkoAAA2AAAMAQsgAygC4AEiACAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQcQpKAAANgADIABBwSkoAAA2AAAMAQsgAygC5AEgBkYEQCABQfADakHhKUENEMsBDAELIAMoAugBIAZGBEAgAUHwA2pB7ylBDhDLAQwBCyADKALsASAGRgRAAn8gASwA+wNBAEgEQCABQQg2AvQDIAEoAvADDAELIAFBCDoA+wMgAUHwA2oLIgBBADoACCAAQtu+zfrEqdOv3QA3AAAMAQsgAygC8AEgBkYEQAJ/IAEsAPsDQQBIBEAgAUEINgL0AyABKALwAwwBCyABQQg6APsDIAFB8ANqCyIAQQA6AAggAELbvsGS1cjVr90ANwAADAELIAMoAvQBIAZGBEACfyABLAD7A0EASARAIAFBCDYC9AMgASgC8AMMAQsgAUEIOgD7AyABQfADagsiAEEAOgAIIABC2765+rSK1K/dADcAAAwBCyADKAL4ASAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQcwpKAAANgADIABBySkoAAA2AAAMAQsgAiAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQdwpKAAANgADIABB2SkoAAA2AAAMAQsCQCAAIAZODQAgBiAAIAMoAsABIgJqIAJBmJUDSmtBtZQDa0oNACAGIABBf3NqIQxBACEEIwBBEGsiCiQAAkACQEHE1zQoAgAiAkHI1zRHBEADQCACKAIcIAxGDQICQCACKAIEIgAEQANAIAAiAigCACIADQAMAgsACwNAIAIgAigCCCICKAIARw0ACwsgAkHI1zRHDQALCyAKIAw2AgQgCkHBEzYCAEECQaDrACAKEDQMAQsgAigCECACQRBqIAIsABtBAEgbIQQLIApBEGokACABIAFBlARqIAQQpgEiAkG5KRA4IgAoAgg2AqgEIAEgACkCADcDoAQgAEIANwIAIABBADYCCCABQaAEakG7KhA3IgAoAgAhBCABIAAoAgQ2AuQDIAEgACgABzYA5wMgAEIANwIAIAAtAAshCiAAQQA2AgggASwA+wNBAEgEQCABKALwAxAvCyABIAQ2AvADIAggASgA5wM2AAMgCCABKALkAzYCACABIAo6APsDIAEsAKsEQQBIBEAgASgCoAQQLwsgASwAnwRBAE4NASACKAIAEC8MAQsgAUGUBGoiACAGEDkgASAAQaQpEDgiACgCCDYCqAQgASAAKQIANwOgBCAAQgA3AgAgAEEANgIIIAFBoARqQbsqEDciACgCACECIAEgACgCBDYC5AMgASAAKAAHNgDnAyAAQgA3AgAgAC0ACyEEIABBADYCCCABLAD7A0EASARAIAEoAvADEC8LIAEgAjYC8AMgCCABKADnAzYAAyAIIAEoAuQDNgIAIAEgBDoA+wMgASwAqwRBAEgEQCABKAKgBBAvCyABLACfBEEATg0AIAEoApQEEC8LIAEgAUHwA2oiADYClAQgAUGgBGogCyAAIAFBlARqEOIEIAEoAqAEIAY2AhwCQAJAIAUiAiIAKAIAIgRFDQADQCAEIgAoAhAiAiAGSgRAIAAiAigCACIEDQEMAgsgAiAGTg0CIAAoAgQiBA0ACyAAQQRqIQILQSAQMiIEIAY2AhAgBCAANgIIIARCADcCACAEQgA3AhQgBEEANgIcIAIgBDYCACAEIQAgAygC0AEoAgAiCgRAIAMgCjYC0AEgAigCACEACyADKALUASAAEKQBIAMgAygC2AFBAWo2AtgBCwJAIARBFGoiACABQfADakYNACABLQD7AyIKwCECIAQsAB9BAE4EQCACQQBOBEAgACABKQPwAzcCACAAIAEoAvgDNgIIDAILIAAgASgC8AMgASgC9AMQ3gEMAQsgACABKALwAyABQfADaiACQQBIIgAbIAEoAvQDIAogABsQ3wELIAZBAWoiBiADKAIgSA0ACwsgAygCwAEhACABQcglNgLQASABIAAgAEGYlQNKa0G1lANrNgLUAUEEQaztACABQdABahA0IAEoArAEIgAEQCABIAA2ArQEIAAQLwsgASwA+wNBAEgEQCABKALwAxAvCyADKAIQIQggAygCMCEAIAMoAkAhAiABQQE6APgDIAEgASgC+AM2AsgBIAEgAEEPbCACQRhsakEZakG8Amw2AvADQQAhACABQQA2AvQDIAEgASkC8AM3A8ABIAMgAUHAAWoQvgEiAjYCqAEgAkUEQCABQcglNgIAQQJBo+oAIAEQNAwBCyADNAJEISUgAygCQCEKIAMoAjghEiADNAI0IScgAygCKCETIAM0AiQhKCADNAIgISkCQCADKAIwIgwgAygClAEiACADKAKQASIEa0E8bSICSwRAQQAhBiAMIAJrIgQgAygCmAEiCyAAa0E8bU0EQCADIAQEfyAAQQAgBEE8bEE8ayICIAJBPHBrQTxqIgL8CwAgACACagUgAAs2ApQBDAILAkAgACADKAKQASIFa0E8bSIQIARqIgJBxYiRIkkEQEHEiJEiIAsgBWtBPG0iC0EBdCIRIAIgAiARSRsgC0GixIgRTxsiCwRAIAtBxYiRIk8NAiALQTxsEDIhBgsgEEE8bCAGaiICQQAgBEE8bEE8ayIEIARBPHBrQTxqIgT8CwAgAiAEaiEEIAAgBUcEQANAIAJBPGsiAiAAQTxrIgD9AAIA/QsCACACIAAoAjg2AjggAiAAKQIwNwIwIAIgAP0AAiD9CwIgIAIgAP0AAhD9CwIQIAAgBUcNAAsgAygCkAEhAAsgAyAGIAtBPGxqNgKYASADIAQ2ApQBIAMgAjYCkAEgAARAIAAQLwsMAwsQNgALEEcACyACIAxNDQAgAyAEIAxBPGxqNgKUAQsgCEEARyEQAkAgAygCoAEiACADKAKcASIEa0HgAG0iAiAKSQRAQQAhBSAKIAJrIgQgAygCpAEiCyAAa0HgAG1NBEAgAyAEBH8gAEEAIARB4ABsQeAAayICIAJB4ABwa0HgAGoiAvwLACAAIAJqBSAACzYCoAEMAgsCQCAAIAMoApwBIgZrQeAAbSIRIARqIgJBq9WqFUkEQEGq1aoVIAsgBmtB4ABtIgtBAXQiGCACIAIgGEkbIAtB1arVCk8bIgsEQCALQavVqhVPDQIgC0HgAGwQMiEFCyARQeAAbCAFaiICQQAgBEHgAGxB4ABrIgQgBEHgAHBrQeAAaiIE/AsAIAIgBGohBCAAIAZHBEADQCACQeAAayICIABB4ABrIgBB4AD8CgAAIAAgBkcNAAsgAygCnAEhAAsgAyAFIAtB4ABsajYCpAEgAyAENgKgASADIAI2ApwBIAAEQCAAEC8LDAMLEDYACxBHAAsgAiAKTQ0AIAMgBCAKQeAAbGo2AqABCyADIAMoAqgBQQAgE6wiJCAoEFU2AmQgAyADKAKoASAQQgMgJSAkELwBNgJoIAMgAygCqAFBAEIBICQQVTYCbCADIAMoAqgBIBBCAyAkICQQvAE2AnAgAyADKAKoAUEAQgEgJBBVNgJ0IAMgAygCqAFBACAkEEg2AnggAyADKAKoAUEAICQQSDYCfCADKAJkIQIgAUEgEDIiADYC8AMgAUKcgICAgISAgIB/NwL0AyAAQZAeKAAANgAYIABBiB4pAAA3ABAgAEH4Hf0AAAD9CwAAIABBADoAHCABIAFB8ANqIgA2AqAEIAFBsARqIANBtAFqIgUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyADKAJoIQIgAUEgEDIiADYC8AMgAUKUgICAgISAgIB/NwL0AyAAQdEOKAAANgAQIABBwQ79AAAA/QsAACAAQQA6ABQgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCbCECIAFBIBAyIgA2AvADIAFCkoCAgICEgICAfzcC9AMgAEGNEy8AADsAECAAQf0S/QAAAP0LAAAgAEEAOgASIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAnAhAiABQSAQMiIANgLwAyABQpSAgICAhICAgH83AvQDIABBrg4oAAA2ABAgAEGeDv0AAAD9CwAAIABBADoAFCABIAFB8ANqIgA2AqAEIAFBsARqIAUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyADKAJ0IQIgAUEgEDIiADYC8AMgAUKSgICAgISAgIB/NwL0AyAAQe4SLwAAOwAQIABB3hL9AAAA/QsAACAAQQA6ABIgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCeCECIAFBIBAyIgA2AvADIAFCloCAgICEgICAfzcC9AMgAEGDDSkAADcADiAAQfUM/QAAAP0LAAAgAEEAOgAWIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAnwhAiABQSAQMiIANgLwAyABQpSAgICAhICAgH83AvQDIABB8hEoAAA2ABAgAEHiEf0AAAD9CwAAIABBADoAFCABIAFB8ANqIgA2AqAEIAFBsARqIAUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyAMQQBKBEAgE0ECdKwhJUEAIQQDQCADKAKQASAEQTxsaiIAIAMoAqgBQQAgJBBINgIkIAAgAygCqAFBACAkEEg2AiggACADKAKoASAIICQgJRBVNgIsIAAgAygCqAFBACAlEEg2AjAgACADKAKoASAIICUgJBBVNgI0IAAgAygCqAFBACAkEEg2AjggACADKAKoAUEAICQQSDYCACAAIAMoAqgBQQAgJBBINgIEIAAgAygCqAEgCCAkICQQVTYCECAAIAMoAqgBQQAgJBBINgIUIAAgAygCqAEgCCAkICQQVTYCGCAAIAMoAqgBIAggJCAkEFU2AhwgACADKAKoAUEAICQQSDYCICAAIAMoAqgBIAggJCAkEFU2AgggACADKAKoAUEAICQQSDYCDCAAKAIkIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQYwNEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIoIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQfcREDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIsIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQdYOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIwIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZATEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAI0IQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbMOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAI4IQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQfESEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIAIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbENEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIEIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZgSEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIQIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZIMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIUIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQa0REDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIYIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbwMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIcIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQYsOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIgIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQc0SEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIIIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQeQMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIMIQIgAUGgBGoiACAEEDkgASAAQc7CABA4IgAoAgg2ArgEIAEgACkCADcDsAQgAEIANwIAIABBADYCCCABIAFBsARqQdMREDciACgCCDYC+AMgASAAKQIANwPwAyAAQgA3AgAgAEEANgIIIAEgAUHwA2oiADYC5AMgAUGUBGogBSAAIAFB5ANqEDwgASgClAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAEQQFqIgQgDEcNAAsLIAMgAygCqAFBACASrCIkICcQVTYCgAEgAyADKAKoASAIICQgKRBVNgKEASADIAMoAqgBQQAgJBBINgKIASADIAMoAqgBQQAgJBBINgKMASADKAKAASECIAFBIBAyIgA2AvADIAFCnICAgICEgICAfzcC9AMgAEGtHigAADYAGCAAQaUeKQAANwAQIABBlR79AAAA/QsAACAAQQA6ABwgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygChAEhAiABQSAQMiIANgLwAyABQp6AgICAhICAgH83AvQDIABB6Q0pAAA3ABYgAEHjDSkAADcAECAAQdMN/QAAAP0LAAAgAEEAOgAeIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAogBIQIgAUEgEDIiADYC8AMgAUKRgICAgISAgIB/NwL0AyAAQdENLQAAOgAQIABBwQ39AAAA/QsAACAAQQA6ABEgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCjAEhAiABQRAQMiIANgLwAyABQo+AgICAgoCAgH83AvQDIABBrRIpAAA3AAcgAEGmEikAADcAACAAQQA6AA8gASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgCkEASgRAIBJBAnSsISVBACEEA0AgAygCnAEgBEHgAGxqIgAgAygCqAFBACAkEEg2AkggACADKAKoAUEAICQQSDYCTCAAIAMoAqgBIAggJCAlEFU2AlAgACADKAKoAUEAICUQSDYCVCAAIAMoAqgBIAggJSAkEFU2AlggACADKAKoAUEAICQQSDYCXCAAIAMoAqgBQQAgJBBINgIAIAAgAygCqAFBACAkEEg2AgQgACADKAKoASAIICQgJBBVNgIQIAAgAygCqAFBACAkEEg2AhQgACADKAKoASAIICQgJBBVNgIYIAAgAygCqAEgCCAkICQQVTYCHCAAIAMoAqgBQQAgJBBINgIgIAAgAygCqAEgCCAkICQQVTYCCCAAIAMoAqgBQQAgJBBINgIMIAAgAygCqAFBACAkEEg2AiQgACADKAKoAUEAICQQSDYCKCAAIAMoAqgBIAggJCAkEFU2AjQgACADKAKoAUEAICQQSDYCOCAAIAMoAqgBIAggJCAkEFU2AjwgACADKAKoASAIICQgJBBVNgJAIAAgAygCqAFBACAkEEg2AkQgACADKAKoASAIICQgJBBVNgIsIAAgAygCqAFBACAkEEg2AjAgACgCSCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGMDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCTCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakH3ERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCUCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHWDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCVCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGQExA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCWCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGzDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCXCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHxEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCACEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGxDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCBCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGYEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCECEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGSDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCFCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGtERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCGCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakG8DBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCHCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGLDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCICEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHNEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCCCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHkDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCDCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHTERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCJCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGbDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCKCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGEEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCNCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakH5CxA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCOCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGWERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCPCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGlDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgAEFAaygCACEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHyDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCRCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakG2EhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCLCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHNDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCMCECIAFBoARqIgAgBBA5IAEgAEHewgAQOCIAKAIINgK4BCABIAApAgA3A7AEIABCADcCACAAQQA2AgggASABQbAEakG+ERA3IgAoAgg2AvgDIAEgACkCADcD8AMgAEIANwIAIABBADYCCCABIAFB8ANqIgA2AuQDIAFBlARqIAUgACABQeQDahA8IAEoApQEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgBEEBaiIEIApHDQALCyADEOUEIgA2AoQCQQAhBCADKAK0ASICIANBuAFqIgZHBEADQCACKAIcEFsgBGohHAJAIAIoAgQiBARAA0AgBCIAKAIAIgQNAAwCCwALA0AgAigCCCIAKAIAIAJHIRsgACECIBsNAAsLIBxBvAJqIQQgBiAAIgJHDQALIAMoAoQCIQALIAMgACAAKAIIEQAAIgAgBCAAKAIAEQQANgKsASADKAKEAiIABH8gACAAKAIAEQAABUGwMAshACABIAS4RAAAAACAhC5BozkDuAEgASAANgK0ASABQcglNgKwAUEEQa3vACABQbABahA0IAMoAqwBEMkBIQwgBiADKAK0ASICRwRAA0AgDCACKAIcEJABAkAgAigCBCIEBEADQCAEIgAoAgAiBA0ADAILAAsDQCACKAIIIgAoAgAgAkchHSAAIQIgHQ0ACwsgBiAAIgJHDQALCyADQQA2ArABIAFBADYCuAQgAUIANwKwBEEAIQoDQAJAIAcoAiQgAUGQBGpBBCAHKAIoEQMAGiAHKAIkIAFBjARqQQQgBygCKBEDABogBygCJCABQYgEakEEIAcoAigRAwAaAkACQAJAIAcoAiQgBygCLBEAAARAIAFByCU2AjAgASAKuEQAAAAAgIQuQaM5AzhBBEGp8QAgAUEwahA0IAMoArABIgANASABQcglNgIQQQNBxOYAIAFBEGoQNEEAIQIMBAtBACEAIAFB0KUB/QAEAP0LBPADQQEhBCABKAKQBEEASg0BDAILQQAhAiAAIAMoArwBIgRGDQIgASAANgIoIAEgBDYCJCABQcglNgIgQQJB1+oAIAFBIGoQNEEBIQIMAgsDQCAHKAIkIAFB8ANqIABBAnRqIgJBBCAHKAIoEQMAGiACKAIAIARsIQQgAEEBaiIAIAEoApAESA0ACwtBACECIAFBADYCqAQgAUIANwOgBCABQQA2ApwEIAFCADcClARBACEAIAEoAowEIggEQCAIQQBIDQQgASAIEDIiADYClAQgASAAIAhqIgI2ApwEIABBACAI/AsAIAEgAjYCmAQLIAcoAiQgACACIABrIgggBygCKBEDABogAUGgBGoiAiAAIAgQywECfyAFIAIQ8AIgBkYEQCABQcglNgJAQQAhBCABIAEoAqAEIAIgASwAqwRBAEgbNgJEQQJB9+cAIAFBQGsQNEEBDAELIAEoAqAEIAFBoARqIAEsAKsEQQBIGyIIEGgiAEHw////B08NBQJAIABBCk0EQCABIAA6AO8DIAFB5ANqIQIMAQsgAEEPckEBaiILEDIhAiABIAtBgICAgHhyNgLsAyABIAI2AuQDIAEgADYC6AMLIAIgCCAA/AoAACAAIAJqQQA6AAAgASABQeQDaiIANgLEBCABQcgEaiAFIAAgAUHEBGoQPCABKALIBCgCHCEAIAEsAO8DQQBIBEAgASgC5AMQLwsgBKwgACkDKCAAKQMgIAApAxggACkDEH5+flIEQCABQcglNgKgAUEAIQQgASABKAKgBCABQaAEaiABLACrBEEASBs2AqQBQQJByecAIAFBoAFqEDQgACkDICEkIAApAxghJSABIAApAxA+ApABIAEgJT4ClAEgASAkPgKYASABQcglNgKAASABIAEoAvADNgKEASABIAEpAvQDNwOIAUECQfzuACABQYABahA0QQEMAQsgACkDGCEkIAEoAvQDIQgCQAJAIAApAxAiJSABKALwAyILrFIEQCABKAL4AyECDAELIAEoAvgDIQIgJCAIrFINACAAKQMgIAKsUQ0BCyABIAApAyA+AnAgASALNgJ0IAEgCDYCeCABIAI2AnwgAUHIJTYCYEEAIQQgASABKAKgBCABQaAEaiABLACrBEEASBs2AmQgASAlPgJoIAEgJD4CbEECQaTuACABQeAAahA0QQEMAQsgBCABKAKIBEEkbEGYmwFqKAIAbCICIAAoAgBBJGxBlJsBaigCAG4gABBbRwRAIAEoAqAEIQggASwAqwQhCyAAEFshACABIAI2AlwgASAANgJYIAFByCU2AlBBACEEIAEgCCABQaAEaiALQQBIGzYCVEECQZviACABQdAAahA0QQEMAQsCQCADKAKEAigCAEE8RgRAIAcoAighAiAHKAIkIAAoAtABIAAQWyACEQMAGgwBCwJAIAAQWyICIAFBsARqIgQoAgQgBCgCACILayIISwRAIAQgAiAIaxDxAgwBCyACIAhJBEAgBCACIAtqNgIECwsgBygCJCABKAKwBCICIAEoArQEIAJrIAcoAigRAwAaIAAgASgCsARBACAAEFsQlwELIAAQWyEeQQEhBCADIAMoArABQQFqNgKwASAeIApqIQpBAAshAiABKAKUBCIABEAgABAvCyABLACrBEEASARAIAEoAqAEEC8LIAQNAQsLIAEoArAEIgAEQCABIAA2ArQEIAAQLwtBACEAIAINACAMEJEBIAMQaSAmfTcDAEEBIQALIAFB0ARqJAAgAAwCCxA2AAsQTQALIR8gBygCJCAHKAIwEQEAIB9FBEAgD0HTHzYCAEECQfPlACAPEDQgAywAkwJBAEgEQCADKAKIAhAvCyAXIAMoAtQBEI8CIBYgAygCyAEQjgIgFSADKAK4ARCNAiADKAKcASIABEAgAyAANgKgASAAEC8LIAMoApABIgAEQCADIAA2ApQBIAAQLwsgAygCWCIABEAgAyAANgJcIAAQLwsgAxAvQQAh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5ZKe4AZsIARqIgA2AgAgA0ECaiIEQQJ0IAJqIABBHnYgAHNB5ZKe4AZsIARqIgA2AgAgA0EDaiIEQfAERwRAIARBAnQgAmogAEEediAAc0Hlkp7gBmwgBGoiADYCACADQQRqIQMMAQsLIAFBADYCwBQgBUHkAmogAUGAAWoiAEHEE/wKAAAgCSgChAIhAiABIAFByBRqNgKIASABQeS1ATYCgAEgASAANgKQASABIAFBzBRqNgKEASAFQZSnAWogAiAAEJACAkACfyAAIAEoApABIgNGBEAgACEDIAEoAoABQRBqDAELIANFDQEgAygCAEEUagshACADIAAoAgARAQALIAEoAsgUIgBBmKcBaigCACECIABBnKcBaigCACEEIAAoApSnASgCACgClBAhACABQcAfNgIwIAEgACAEIAJrarhEAAAAAICELkGjOQM4QQRBgfEAIAFBMGoQNCABKALMFCgChAIhAiABKALIFCEhIAEgAUHIFGo2AogBIAFB1LcBNgKAASABIAFBgAFqIgA2ApABIAEgAUHMFGo2AoQBICFBqKcBaiACIAAQkAICQAJ/IAAgASgCkAEiA0YEQCAAIQMgASgCgAFBEGoMAQsgA0UNASADKAIAQRRqCyEAIAMgACgCABEBAAsgASgCyBQiAEGspwFqKAIAIQIgAEGwpwFqKAIAIQQgACgCqKcBKAIAKAKUECEAIAFBwB82AiAgASAAIAQgAmtquEQAAAAAgIQuQaM5AyhBBEHr7wAgAUEgahA0IAEoAswUKAKEAiECIAEoAsgUISIgASABQcgUajYCiAEgAUGMuQE2AoABIAEgAUGAAWoiADYCkAEgASABQcwUajYChAEgIkG8pwFqIAIgABCQAgJAAn8gACABKAKQASIDRgRAIAAhAyABKAKAAUEQagwBCyADRQ0BIAMoAgBBFGoLIQAgAyAAKAIAEQEACyABKALIFCIAQcCnAWooAgAhAiAAQcSnAWooAgAhBCAAKAK8pwEoAgAoApQQIQAgAUHAHzYCECABIAAgBCACa2q4RAAAAACAhC5BozkDGEEEQdnwACABQRBqEDQgASgCzBQoAoQCIQIgASgCyBQhIyABIAFByBRqNgKIASABQcS6ATYCgAEgASABQYABaiIANgKQASABIAFBzBRqNgKEASAjQdCnAWogAiAAEJACAkACfyAAIAEoApABIgNGBEAgACEDIAEoAoABQRBqDAELIANFDQEgAygCAEEUagshACADIAAoAgARAQALIAEoAsgUIgBB1KcBaigCACECIABB2KcBaigCACEEIAAoAtCnASgCACgClBAhACABQcAfNgIAIAEgACAEIAJrarhEAAAAAICELkGjOQMIQQRBk/AAIAEQNCABKALIFCIDKAKUpwEiAgRAIAEoAswUKAKEAiEAIAIoAgAoApQQIQIgAygClKcBEJEBIANBpKcBaiAAIAAoAggRAAAiACACIAAoAgARBAAiADYCACADIAAQyQE2ApSnASABKALIFCEDCyADKAKopwEiAARAIAEoAswUKAKEAiECIAAoAgAoApQQIQQgABCRASADQbinAWogAiACKAIIEQAAIgAgBCAAKAIAEQQAIgA2AgAgAyAAEMkBNgKopwEgASgCyBQhAwsgAygCvKcBIgAEQCABKALMFCgChAIhAiAAKAIAKAKUECEEIAAQkQEgA0HMpwFqIAIgAigCCBEAACIAIAQgACgCABEEACIANgIAIAMgABDJATYCvKcBIAEoAsgUIQMLIAMoAtCnASIARQ0AIAEoAswUKAKEAiECIAAoAgAoApQQIQQgABCRASADQeCnAWogAiACKAIIEQAAIgAgBCAAKAIAEQQAIgA2AgAgAyAAEMkBNgLQpwEgASgCyBQhAwsgAUHQFGokACADDAELEDYACyIANgKAAiAJIAANARogCRDgBAtBAAsiADYCACAAQQBHCwvqBQIEfwJ8IwBBIGsiBCQAIAQgADYCACAEQQA6ABggBEIANwMQIAQgAjYCDCAEIAE2AgggBCMDNgIEAnwgAwRAIwBBEGsiAyQAIAMgBDYCDCADQQA2AgggA0HIATYCBCADQQRqIQUjAEGAAWsiACQAIwBB4ABrIgEkAAJAQYTzNCgCAEECRgRAIwBBEGtBADYCDAwBCyMAQRBrIgIkAANAAkACQAJAAkACQEGE8zRBAEEB/kgCAA4EAAIBAwULIAJBBGoiBkGE8zQ2AgQgAkHKATYCBCACIwMiBygCRDYCDCAHIAY2AkQQmAQjAyACKAIMNgJEQYTzNEEC/kECAEEDRw0AQYTzNBD6AQsgAkEQaiQADAILQYTzNEEBQQP+SAIAGgtBhPM0QQBBAxChAQwBCwsLIAFBAEHQAPwL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QQAhBgNAIAEgICAEIA/9GwFqIgosAABBIGuylP0TIg39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgFCAH/Q8iDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAcIA/9GwAiAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwIwIAEgDf0M/P////z////8/////P////0MAAAAAAAAAAAAAAAAAAAAACAVIA79Tv0MAAAAAAAAAAAAAAAAAAAAAP0j/YcB/acB/VIgHSAC/a0B/QwDAAAAAwAAAAMAAAADAAAA/U79UP36Af3mAf0LAiAgASAN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBYgDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAeIAL9rQH9DAMAAAADAAAAAwAAAAMAAAD9Tv1Q/foB/eYB/QsCECABIA39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgFyAO/U79DAAAAAAAAAAAAAAAAAAAAAD9I/2HAf2nAf1SIB8gAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwIAIAEgICAKLAABQSBrspT9EyIN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBAgDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAYIAL9rQH9DAMAAAADAAAAAwAAAAMAAAD9Tv1Q/foB/eYB/QsCcCABIA39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgESAO/U79DAAAAAAAAAAAAAAAAAAAAAD9I/2HAf2nAf1SIBkgAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwJgIAEgDf0M/P////z////8/////P////0MAAAAAAAAAAAAAAAAAAAAACASIA79Tv0MAAAAAAAAAAAAAAAAAAAAAP0j/YcB/acB/VIgGiAC/a0B/QwDAAAAAwAAAAMAAAADAAAA/U79UP36Af3mAf0LAlAgASAN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBMgDv1O/QwAAAAAAAAAAAAA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JCACIANGIQkgAkEEaiECIAlFDQALDAELIAEgACgCCDYCKAsLjgcCBH8EeyACQR9KBEAgAkEgbSEGA0AgASAFQQd0aiIDQUBrIAAgBUEWbGoiBC8BAEECdEGQ1gRq/QkCACIHIAQoAQIiAkEMdv0RIAJBDXb9HAEgAkEOdv0cAiACQQ92/RwDIgn9DBAAAAAQAAAAEAAAABAAAAD9TiAE/VwABv2JAf2pASIIQQT9rQH9UP0M8P////D////w////8P////2uAf36Af3mAf0LAgAgAyAHIAJBBHT9ESACQQN0/RwBIAJBAnT9HAIgAkEBdP0cA/0MEAAAABAAAAAQAAAAEAAAAP1OIAj9DA8AAAAPAAAADwAAAA8AAAD9Tv1Q/Qzw////8P////D////w/////a4B/foB/eYB/QsCACADIAcgAkEQdv0RIAJBEXb9HAEgAkESdv0cAiACQRN2/RwD/QwQAAAAEAAAABAAAAAQAAAA/U4gBEEKav1cAAD9iQH9qQEiCEEE/a0B/VD9DPD////w////8P////D////9rgH9+gH95gH9CwJQIAMgByACQQR2/REgAkEFdv0cASACQQZ2/RwCIAJBB3b9HAMiCkEE/asB/QwQAAAAEAAAABAAAAAQAAAA/U4gCP0MDwAAAA8AAAAPAAAADwAAAP1O/VD9DPD////w////8P////D////9rgH9+gH95gH9CwIQIAMgByACQRR2/REgAkEVdv0cASACQRZ2/RwCIAJBF3b9HAP9DBAAAAAQAAAAEAAAABAAAAD9TiAEQQ5q/VwAAP2JAf2pASIIQQT9rQH9UP0M8P////D////w////8P////2uAf36Af3mAf0LAmAgAyAHIAr9DBAAAAAQAAAAEAAAABAAAAD9TiAI/QwPAAAADwAAAA8AAAAPAAAA/U79UP0M8P////D////w////8P////2uAf36Af3mAf0LAiAgAyAHIAJBGHb9ESACQRl2/RwBIAJBGnb9HAIgAkEbdv0cA/0MEAAAABAAAAAQAAAAEAAAAP1OIARBEmr9XAAA/YkB/akBIghBBP2tAf1Q/Qzw////8P////D////w/////a4B/foB/eYB/QsCcCADIAcgCUEE/asB/QwQAAAAEAAAABAAAAAQAAAA/U4gCP0MDwAAAA8AAAAPAAAADwAAAP1O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IAAoAgQ2AigPCwsgAUGfeDYCACABQQA2AigPCxD/AQALnQEBBH8CQAJAIAEoAhAgACgCFEEBa0EMbGoiAi0ACEUNASACKAIEIAIoAgAiBWsiAyABKAIMIAEoAggiBGtKDQFBACECIANBAEwNAANAIAIgBWotAAAgAiAEai0AAEcNAiADIAJBAWoiAkcNAAsMAAsgAUGeeDYCACABIAMgBGo2AgggASAAKAIENgIoDwsgAUGfeDYCACABQQA2AigLUgEBfyAAQcyvATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwtQAQF/IABBzK8BNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgAAvPAQEEfwJAAkACQCABKAIQIAAoAhRBDGxqQQxrIgMtAAhFDQIgAygCBCADKAIAayIEIAEoAgwgASgCCCICa0oNAiAEQQBMDQFBACECA0AgACgCDCIFIAMoAgAgAmosAAAgBSgCACgCFBEEACAAKAIMIgUgASgCCCACaiwAACAFKAIAKAIUEQQARw0DIAQgAkEBaiICRw0ACwwACyABKAIIIQILIAFBnng2AgAgASACIARqNgIIIAEgACgCBDYCKA8LIAFBn3g2AgAgAUEANgIoC1IBAX8gAEH0rgE2AgAgACgCCCIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgAEHcqQE2AgAgACgCBCIBBEAgASABKAIAKAIEEQEACyAAEC8LUAEBfyAAQfSuATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAALjQQCAnsDfyACQR9KBEAgAkEgbSEHA0AgASAFQQd0aiICQUBrIAAgBUESbGoiBi8BAEECdEGQ1gRq/QkCACIDIAb9XAAC/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAgAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAgAgAiADIAZBBmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAlAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAhAgAiADIAZBCmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAmAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAiAgAiADIAZBDmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAnAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAjAgBUEBaiIFIAdHDQALCwtPAQF/AkAgASgCCCICIAEoAgxGDQAgAi0AACAALQAIRw0AIAFBnXg2AgAgASACQQFqNgIIIAEgACgCBDYCKA8LIAFBn3g2AgAgAUEANgIoC08BAX8CQCABKAIIIgIgASgCDEYNACACLQAAIAAtABRHDQAgAUGdeDYCACABIAJBAWo2AgggASAAKAIENgIoDwsgAUGfeDYCACABQQA2AigLUgEBfyAAQditATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwtQAQF/IABB2K0BNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgAAtoAQJ/AkAgASgCCCICIAEoAgxGDQAgACgCDCIDIAIsAAAgAygCACgCFBEEAEH/AXEgAC0AFEcNACABQZ14NgIAIAEgASgCCEEBajYCCCABIAAoAgQ2AigPCyABQZ94NgIAIAFBADYCKAtSAQF/IABB/KwBNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgABAvC1ABAX8gAEH8rAE2AgAgACgCCCIBQQRqQX/+HgIARQRA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b2FkY2FzdAB1bnNpZ25lZCBzaG9ydABhbGVydAB3aGlzcGVyX2t2X2NhY2hlX2ZpbmRfc2xvdABwcmludAB1bnNpZ25lZCBpbnQAY2lyY3VtZmxleC1hY2NlbnQAZ3JhdmUtYWNjZW50AGZ1bGxfZGVmYXVsdABrdl9jYWNoZV9pbml0AHhkaWdpdAAuY3Jvc3NfYXR0bi5xdWVyeS53ZWlnaHQALmF0dG4ucXVlcnkud2VpZ2h0AC5jcm9zc19hdHRuLmtleS53ZWlnaHQALmF0dG4ua2V5LndlaWdodAAuY3Jvc3NfYXR0bi5vdXQud2VpZ2h0AC5hdHRuLm91dC53ZWlnaHQAZW5jb2Rlci5sbl9wb3N0LndlaWdodAAubWxwX2xuLndlaWdodAAuY3Jvc3NfYXR0bl9sbi53ZWlnaHQALmF0dG5fbG4ud2VpZ2h0AGRlY29kZXIubG4ud2VpZ2h0AGRlY29kZXIudG9rZW5fZW1iZWRkaW5nLndlaWdodAAuY3Jvc3NfYXR0bi52YWx1ZS53ZWlnaHQALmF0dG4udmFsdWUud2VpZ2h0AGVuY29kZXIuY29udjIud2VpZ2h0AC5tbHAuMi53ZWlnaHQAZW5jb2Rlci5jb252MS53ZWlnaHQALm1scC4wLndlaWdodABzZXQAcmlnaHQtY3VybHktYnJhY2tldABsZWZ0LWN1cmx5LWJyYWNrZXQAcmlnaHQtc3F1YXJlLWJyYWNrZXQAbGVmdC1zcXVhcmUtYnJhY2tldABwdW5jdABnZ21sX25ld19vYmplY3QAT2N0AGZsb2F0AFNhdABjb21tZXJjaWFsLWF0AHVpbnQ2NF90AGh5cGhlbi1taW51cwByZXZlcnNlLXNvbGlkdXMAd2hpc3Blcl9leHBfY29tcHV0ZV90b2tlbl9sZXZlbF90aW1lc3RhbXBzAGFmcmlrYWFucwBwYXJhbXMAZ2dtbF9nZXRfbl90YXNrcwByaWdodC1wYXJlbnRoZXNpcwBsZWZ0LXBhcmVudGhlc2lzAHdoaXNwZXJfcHJpbnRfdGltaW5ncwAuY3Jvc3NfYXR0bi5xdWVyeS5iaWFzAC5hdHRuLnF1ZXJ5LmJpYXMALmNyb3NzX2F0dG4ub3V0LmJpYXMALmF0dG4ub3V0LmJpYXMAZW5jb2Rlci5sbl9wb3N0LmJpYXMALm1scF9sbi5iaWFzAC5jcm9zc19hdHRuX2xuLmJpYXMALmF0dG5fbG4uYmlhcwBkZWNvZGVyLmxuLmJpYXMALmNyb3NzX2F0dG4udmFsdWUuYmlhcwAuYXR0bi52YWx1ZS5iaWFzAGVuY29kZXIuY29udjIuYmlhcwAubWxwLjIuYmlhcwBlbmNvZGVyLmNvbnYxLmJpYXMALm1scC4wLmJpYXMAcm93X2lkID49IDAgJiYgcm93X2lkIDwgbl9hcwAlcwBmb3VyAHdoaXNwZXJfbGFuZ19zdHIAQXByAGNvbnN0cnVjdG9yAHZlY3RvcgBjZ3JhcGgtPm5vZGVzW2NncmFwaC0+bl9ub2RlcyAtIDFdID09IHRlbnNvcgB1bmtub3duIGFsbG9jYXRpb24gZXJyb3IAYmFzaGtpcgBsb3dlcgB1cHBlcgBraG1lcgBidWZmZXIAT2N0b2JlcgBOb3ZlbWJlcgBTZXB0ZW1iZXIARGVjZW1iZXIAdGF0YXIAbXlhbm1hcgB1bnNpZ25lZCBjaGFyAGlvc19iYXNlOjpjbGVhcgBNYXIAcQAvVXNlcnMvZ2dlcmdhbm92L2RldmVsb3BtZW50L2dpdGh1Yi93aGlzcGVyLmNwcC93aGlzcGVyLmNwcABmdWxsLXN0b3AAU2VwACVJOiVNOiVTICVwAHR3bwBhdXRvAHBhc2h0bwB6ZXJvAGxhbwB1bmtub3duAFN1bgBKdW4AY2FycmlhZ2UtcmV0dXJuAGJyZXRvbgBzZW1pY29sb24Ac3RkOjpleGNlcHRpb24AX19jeGFfZ3VhcmRfYWNxdWlyZSBkZXRlY3RlZCByZWN1cnNpdmUgaW5pdGlhbGl6YXRpb24ATW9uAGxhdGluAHBlcmNlbnQtc2lnbgBwbHVzLXNpZ24AZXF1YWxzLXNpZ24AbnVtYmVyLXNpZ24AZG9sbGFyLXNpZ24AbGVzcy10aGFuLXNpZ24AZ3JlYXRlci10aGFuLXNpZ24Ac2V2ZW4AdHVya21lbgBoeXBoZW4Ab2NjaXRhbgB0aWJldGFuAG5hbgBnZXJtYW4AY3BsYW4AY2F0YWxhbgBsYXR2aWFuAGJlbGFydXNpYW4AcnVzc2lhbgBwZXJzaWFuAGluZG9uZXNpYW4AaHVuZ2FyaWFuAGJ1bGdhcmlhbgBib3NuaWFuAG1hY2Vkb25pYW4AdWtyYWluaWFuAHNsb3ZlbmlhbgBsaXRodWFuaWFuAG1vbmdvbGlhbgBpdGFsaWFuAG5vcndlZ2lhbgBzZXJiaWFuAGtvcmVhbgBKYW4AYWxudW0AbWVkaXVtAG1hbGF5YWxhbQBKdWwAY250cmwAZ2dtbF9uZXdfdGVuc29yX2ltcGwAYm9vbABzbWFsbABzdGQ6OmJhZF9mdW5jdGlvbl9jYWxsAEFwcmlsAHRhbWlsAGVtc2NyaXB0ZW46OnZhbABueW5vcnNrAGFzdGVyaXNrAHF1ZXN0aW9uLW1hcmsAcXVvdGF0aW9uLW1hcmsAZXhjbGFtYXRpb24tbWFyawBibGFuawB0YWppawBncmVlawB1emJlawBzbG92YWsAagBtYW9yaQBGcmkAYXplcmJhaWphbmkAc3dhaGlsaQBuZXBhbGkAc29tYWxpAGJlbmdhbGkAbWFyYXRoaQBzaW5kaGkAaGluZGkAcHVuamFiaQBiYWRfYXJyYXlfbmV3X2xlbmd0aAB3ZWxzaABmaW5uaXNoAHNwYW5pc2gAZGFuaXNoAHBvbGlzaABlbmdsaXNoAHR1cmtpc2gAbHV4ZW1ib3VyZ2lzaABzd2VkaXNoAHlpZGRpc2gAYmFja3NsYXNoAGdyYXBoAGthemFraABkdXRjaABNYXJjaABmcmVuY2gAY3plY2gAQXVnAHRhZ2Fsb2cAdW5zaWduZWQgbG9uZwB0ZXJtaW5hdGluZwBzdGQ6OndzdHJpbmcAYmFzaWNfc3RyaW5nAHN0ZDo6c3RyaW5nAHN0ZDo6dTE2c3RyaW5nAHN0ZDo6dTMyc3RyaW5nAGVuY29kZXIucG9zaXRpb25hbF9lbWJlZGRpbmcAZGVjb2Rlci5wb3NpdGlvbmFsX2VtYmVkZGluZwBpbmYAJS4wTGYAJUxmAGNncmFwaC0+bl9sZWFmcyA8IGNncmFwaC0+c2l6ZQBjZ3JhcGgtPm5fbm9kZXMgPCBjZ3JhcGgtPnNpemUAd2hpc3Blcl90b2tlbml6ZQBmaXZlAHl1ZQB0cnVlAGJhc3F1ZQBpbnZhbGlkIGFsaWdubWVudCB2YWx1ZQBUdWUAd2hpc3Blcl9pbml0X3N0YXRlAHdoaXNwZXJfaW5pdF93aXRoX3BhcmFtc19ub19zdGF0ZQB3aGlzcGVyX2luaXRfZnJvbV9maWxlX3dpdGhfcGFyYW1zX25vX3N0YXRlAHdoaXNwZXJfbGFuZ19hdXRvX2RldGVjdF93aXRoX3N0YXRlAHdoaXNwZXJfZnVsbF93aXRoX3N0YXRlAHdoaXNwZXJfZW5jb2RlX3dpdGhfc3RhdGUAd2hpc3Blcl9kZWNvZGVfd2l0aF9zdGF0ZQB0cmFuc2xhdGUAZmFsc2UAcG9ydHVndWVzZQBtYWx0ZXNlAGZhcm9lc2UAY2FudG9uZXNlAGNoaW5lc2UAc3VuZGFuZXNlAHZpZXRuYW1lc2UAX19jeGFfZ3VhcmRfcmVsZWFzZQB1bmRlcnNjb3JlAF9fY3hhX2d1YXJkX2FjcXVpcmUAc3JjMC0+dHlwZSA9PSBkc3QtPnR5cGUAZHN0LT50eXBlID09IHNyYzAtPnR5cGUAVW5rbm93biBlcnJvciB0eXBlAEp1bmUAb25lAG5pbmUAbmV3bGluZQBsb3ctbGluZQB2ZXJ0aWNhbC1saW5lAGhhaXRpYW4gY3Jlb2xlAGRvdWJsZQBhcG9zdHJvcGhlAGxhcmdlAHRocmVlAGZyZWUAdGlsZGUAcmlnaHQtYnJhY2UAbGVmdC1icmFjZQBiYWNrc3BhY2UAdHJhbnNjcmliZQBwZXJpb2QAbWFwOjphdDogIGtleSBub3QgZm91bmQAYW1wZXJzYW5kAHZvaWQAd2hpc3Blcl9sYW5nX2lkAHRlcm1pbmF0ZV9oYW5kbGVyIHVuZXhwZWN0ZWRseSByZXR1cm5lZAB0aHJlYWQgY29uc3RydWN0b3IgZmFpbGVkAF9fdGhyZWFkX3NwZWNpZmljX3B0ciBjb25zdHJ1Y3Rpb24gZmFpbGVkAHRocmVhZDo6am9pbiBmYWlsZWQAbXV0ZXggbG9jayBmYWlsZWQAZm9ybS1mZWVkAFdlZAB3aGlzcGVyX21vZGVsX2xvYWQAJTAyZDolMDJkOiUwMmQlcyUwM2QAbGVhZl8lZABub2RlXyVkAGdnbWxfYWxpZ25lZF9tYWxsb2MAZ2dtbF90YWxsb2NyX2FsbG9jAHN0ZDo6YmFkX2FsbG9jAGRzdC0+bmVbMF0gPT0gbmMAYW1oYXJpYwBpY2VsYW5kaWMAYXJhYmljAERlYwAvVXNlcnMvZ2dlcmdhbm92L2RldmVsb3BtZW50L2dpdGh1Yi93aGlzcGVyLmNwcC9nZ21sLmMAL1VzZXJzL2dnZXJnYW5vdi9kZXZlbG9wbWVudC9naXRodWIvd2hpc3Blci5jcHAvZ2dtbC1iYWNrZW5kLmMAL1VzZXJzL2dnZXJnYW5vdi9kZXZlbG9wbWVudC9naXRodWIvd2hpc3Blci5jcHAvZ2dtbC1hbGxvYy5jAHdiAHJiAEZlYgB2ZXJ0aWNhbC10YWIAbl9sb2dpdHMgPT0gY3R4LnZvY2FiLm5fdm9jYWIAdytiAHIrYgBhK2IAcndhAGNwbGFuLT53b3JrX2RhdGEAaGF1c2EAc2hvbmEAY29tbWEAc2luaGFsYQBsaW5nYWxhAGFscGhhAGthbm5hZGEAeW9ydWJhAFtfZXh0cmFfdG9rZW5fAFtfVFRfAFtfTEFOR18AW19TT1RfXQBbX05PVF9dAFtfRU9UX10AW19CRUdfXQBbX1RSQU5TTEFURV9dAFtfVFJBTlNDUklCRV9dAGEtPm5lWzJdID09IGItPm5lWzJdAGEtPm5lWzJdID09IGItPm5lWzFdAGEtPm5lWzFdID09IGItPm5lWzFdAFoAdGVuc29yLT5vcCA9PSBHR01MX09QX1VOQVJZAE1BUF9VTkFSWQBNQVBfQklOQVJZAENQWQAlYSAlYiAlZCAlSDolTTolUyAlWQBQT1NJWABTT0ZUX01BWABBUkdNQVgAVklFVwBESVYAQ1BVAExFQUtZX1JFTFUAU1FSVABBUkdTT1JUAFdJTl9QQVJUAFdJTl9VTlBBUlQAaXNfcG9zaXRpdmVfY2hhciB8fCBwb3MtPnR5cGUgPT0gV0hJU1BFUl9HUkVUWVBFX0NIQVJfTk9UAHd0eXBlICE9IEdHTUxfVFlQRV9DT1VOVABDT05UAFNFVABNVUxfTUFUAFJFUEVBVABDT05DQVQAR0VUX1JPV1MAU1VNX1JPV1MAQ1JPU1NfRU5UUk9QWV9MT1NTAEdFVF9SRUxfUE9TAEFERF9SRUxfUE9TAGF4aXMzID49IDAgJiYgYXhpczMgPCBHR01MX01BWF9ESU1TAGF4aXMyID49IDAgJiYgYXhpczIgPCBHR01MX01BWF9ESU1TAGF4aXMxID49IDAgJiYgYXhpczEgPCBHR01MX01BWF9ESU1TAGF4aXMwID49IDAgJiYgYXhpczAgPCBHR01MX01BWF9ESU1TACVIOiVNOiVTAFNRUgBRAERVUABDTEFNUABESUFHX01BU0tfWkVSTwBGTEFTSF9BVFROAE5BTgBNRUFOAG5lMSA9PSBOAG5lZDEgPT0gTgBTVU0AUk1TX05PUk0AR1JPVVBfTk9STQBQTQBBTQBuZWIxMCA9PSBNAG5lYzAwID09IE0ATlVMAE1VTABJTTJDT0wAdGVuc29yLT5kYXRhID09IE5VTEwAaGFzaF9zZXQua2V5c1tpXSA9PSBOVUxMAHRlbnNvciAhPSBOVUxMAGN0eC0+bWVtX2J1ZmZlciAhPSBOVUxMAHZpZXctPnZpZXdfc3JjICE9IE5VTEwgJiYgdmlldy0+dmlld19zcmMtPmRhdGEgIT0gTlVMTABpICE9IEdHTUxfSEFTSFRBQkxFX0ZVTEwATENfQUxMAHE4X0sAcTZfSwBxNV9LAHE0X0sAcTNfSwBxMl9LAFNPRlRfTUFYX0JBQ0sAU0lMVV9CQUNLAFJFUEVBVF9CQUNLAEdFVF9ST1dTX0JBQ0sAQ1JPU1NfRU5UUk9QWV9MT1NTX0JBQ0sARkxBU0hfQVRUTl9CQUNLAFJNU19OT1JNX0JBQ0sAUk9QRV9CQUNLAEoAQUxJQkkASABMT0cATEFORwBESUFHAERJQUdfTUFTS19JTkYARkxBU0hfRkYAUEVSTVVURQBUUkFOU1BPU0UAUk9QRQBSRVNIQVBFAE5PTkUAVVBTQ0FMRQBPVVRfUFJPRABNVUxfTUFUX0lEAERFUFJFQ0FURUQAQUREAFBBRABQT09MXzJEAENPTlZfVFJBTlNQT1NFXzJEAFBPT0xfMUQAQ09OVl9UUkFOU1BPU0VfMUQAbmV2MSA9PSBEAG5lYzAxID09IEQAbmVrMCA9PSBEAG5lMCA9PSBEAG5lZDAgPT0gRABuZWMxMCA9PSBEAG5lYjAwID09IEQAQUNDAFNVQgBBAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNob3J0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBpbnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGZsb2F0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50OF90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50NjRfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50NjRfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDMyX3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDMyX3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGNoYXI+AHN0ZDo6YmFzaWNfc3RyaW5nPHVuc2lnbmVkIGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxkb3VibGU+AD4+PgA8PDwAMDEyMzQ1Njc4OQBpOABIRUFQVTgAQy5VVEYtOABpMTYAZjE2AGRzdC0+dHlwZSA9PSBHR01MX1RZUEVfRjE2AHNyYzAtPnR5cGUgPT0gR0dNTF9UWVBFX0YxNgAgdjMAYXhpczIgIT0gYXhpczMAYXhpczEgIT0gYXhpczMAYXhpczAgIT0gYXhpczMAbmUwMyA9PSBuZTMAbmIyIDw9IG5iMwBNQVBfQ1VTVE9NMwBuZTMgPT0gbmUxMwBuZTAzID09IG5lMTMAbmUzID09IG5lMDMAYXhpczEgIT0gYXhpczIAYXhpczAgIT0gYXhpczIAZ2dtbF9uZWxlbWVudHMoYSkgPT0gbmUwKm5lMSpuZTIAbl9oZWFkID09IG5lMgBuZTAyID09IG5lMgBuYjEgPD0gbmIyAG5lMiA9PSBuZWEyAE1BUF9DVVNUT00yAGkzMgBmMzIAYi0+dHlwZSA9PSBHR01MX1RZUEVfSTMyAGRzdC0+dHlwZSA9PSBHR01MX1RZUEVfRjMyAHNyYzEtPnR5cGUgPT0gR0dNTF9UWVBFX0YzMgBNQVBfQ1VTVE9NM19GMzIATUFQX0NVU1RPTTJfRjMyAE1BUF9DVVNUT00xX0YzMgBuZTIgPT0gbmUxMgBuZTAyID09IG5lMTIAbmUyID09IG5lMDIAYXhpczAgIT0gYXhpczEAZ2dtbF9uZWxlbWVudHMoYSkgPT0gbmUwKm5lMQBuZTAwID09IG5lMQBuYjAgPD0gbmIxAG5lMSA9PSBuZWExAHE4XzEAcTVfMQBxNF8xAE1BUF9DVVNUT00xAEFERDEAbmUxID09IG5lMTEAbmUxID09IG5lMDEAbmUwID09IG5lMDEAdCA9PSAwIHx8IHQgPT0gMQBtYXNrLT5uZVszXSA9PSAxAGItPm5lWzNdID09IDEAbm9kZS0+c3JjWzFdLT5uZVszXSA9PSAxAG5vZGUtPnNyY1swXS0+bmVbM10gPT0gMQBtYXNrLT5uZVsyXSA9PSAxAG5vZGUtPnNyY1sxXS0+bmVbMl0gPT0gMQBuZWMxMSA9PSAxAG5lYjExID09IDEAbmUwMSA9PSAxAG5lMCA9PSAxAGdnbWxfYmxja19zaXplKHJlc3VsdF90eXBlKSA9PSAxAGswID09IHMwAG5lMDAgPT0gbmUwAG5fZGltcyA8PSBuZTAAbmUwID09IG5lYTAAcThfMABxNV8wAHE0XzAAbmUxID09IG5lMTAAbmUwID09IG5lMDAAY3BsYW4tPm5fdGhyZWFkcyA+IDAAbl9wYXN0ID49IDAAUCA+PSAwAHBhcmFtcy0+aXRoID09IDAAcmMgPT0gMAAoKHVpbnRwdHJfdCkgKG1lbV9idWZmZXIgKyBvYmpfbmV3LT5vZmZzKSklR0dNTF9NRU1fQUxJR04gPT0gMAAoKHVpbnRwdHJfdCkgKGN0eC0+bWVtX2J1ZmZlcikpJUdHTUxfTUVNX0FMSUdOID09IDAAbl9kaW1zICUgMiA9PSAwAHAwID09IDAAVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgeyBhbmQgfS4AZW5jb2Rlci5ibG9ja3MuAGRlY29kZXIuYmxvY2tzLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCBjaGFyYWN0ZXIgcmFuZ2UsIHN1Y2ggYXMgW2ItYV0gaW4gbW9zdCBlbmNvZGluZ3MuAEFuIGVtcHR5IHJlZ2V4IGlzIG5vdCBhbGxvd2VkIGluIHRoZSBQT1NJWCBncmFtbWFyLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCByYW5nZSBpbiBhIHt9IGV4cHJlc3Npb24uAFRoZSBwYXJzZXIgZGlkIG5vdCBjb25zdW1lIHRoZSBlbnRpcmUgcmVndWxhciBleHByZXNzaW9uLgBPbmUgb2YgKj8reyB3YXMgbm90IHByZWNlZGVkIGJ5IGEgdmFsaWQgcmVndWxhciBleHByZXNzaW9uLgBUaGUgY29tcGxleGl0eSBvZiBhbiBhdHRlbXB0ZWQgbWF0Y2ggYWdhaW5zdCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBleGNlZWRlZCBhIHByZS1zZXQgbGV2ZWwuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGVzY2FwZWQgY2hhcmFjdGVyLCBvciBhIHRyYWlsaW5nIGVzY2FwZS4AVGhlcmUgd2FzIGluc3VmZmljaWVudCBtZW1vcnkgdG8gY29udmVydCB0aGUgZXhwcmVzc2lvbiBpbnRvIGEgZmluaXRlIHN0YXRlIG1hY2hpbmUuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGNvbGxhdGluZyBlbGVtZW50IG5hbWUuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGNoYXJhY3RlciBjbGFzcyBuYW1lLgBUaGVyZSB3YXMgaW5zdWZmaWNpZW50IG1lbW9yeSB0byBkZXRlcm1pbmUgd2hldGhlciB0aGUgcmVndWxhciBleHByZXNzaW9uIGNvdWxkIG1hdGNoIHRoZSBzcGVjaWZpZWQgY2hhcmFjdGVyIHNlcXVlbmNlLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCBiYWNrIHJlZmVyZW5jZS4AQW4gaW52YWxpZCByZWdleCBncmFtbWFyIGhhcyBiZWVuIHJlcXVlc3RlZC4AVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgWyBhbmQgXS4AVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgKCBhbmQgKS4ALS0tAHcrACdzfCd0fCdyZXwndmV8J218J2xsfCdkfCA/W1s6YWxwaGE6XV0rfCA/W1s6ZGlnaXQ6XV0rfCA/W15cc1s6YWxwaGE6XVs6ZGlnaXQ6XV0rfFxzKyg/IVxTKXxccysAcisAYSsAJXMgKGNvcHkpACVzICh2aWV3KQBnZ21sX2JhY2tlbmRfaXNfY3B1KGJhY2tlbmRfY3B1KQBnZ21sX2lzX2NvbnRpZ3VvdXMoZHN0KQBvZmZzZXQgKyBpbTAqbmIwICsgaW0xKm5iMSArIGltMipuYjIgKyBpbTMqbmIzIDw9IGdnbWxfbmJ5dGVzKGRzdCkAb2Zmc2V0ICsgKG5lMTAgPT0gMCA/IDAgOiBuZTEwLTEpKm5iMCArIChuZTExID09IDAgPyAwIDogbmUxMS0xKSpuYjEgKyAobmUxMiA9PSAwID8gMCA6IG5lMTItMSkqbmIyICsgKG5lMTMgPT0gMCA/IDAgOiBuZTEzLTEpKm5iMyA8IGdnbWxfbmJ5dGVzKGRzdCkAZ2dtbF9pc19zY2FsYXIoZHN0KQBnZ21sX2lzX2NvbnRpZ3VvdXNfZXhjZXB0X2RpbV8xKGRzdCkAZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMxLCBkc3QpAGdnbWxfY2FuX3JlcGVhdChzcmMwLCBkc3QpAGdnbWxfYXJlX3NhbWVfc2hhcGUoc3JjMCwgc3JjMSkgJiYgZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBkc3QpAGdnbWxfY2FuX3JlcGVhdChzcmMxLCBzcmMwKSAmJiBnZ21sX2FyZV9zYW1lX3NoYXBlKHNyYzAsIGRzdCkAJXMgKGNvbnQpAGRzdC0+bmJbMF0gPT0gc2l6ZW9mKGZsb2F0KQBzcmMwLT5uYlswXSA9PSBzaXplb2YoZmxvYXQpAG5idjAgPT0gc2l6ZW9mKGZsb2F0KQBuYnEwID09IHNpemVvZihmbG9hdCkAbmJrMCA9PSBzaXplb2YoZmxvYXQpAG5iMCA9PSBzaXplb2YoZmxvYXQpAG5iYzEwID09IHNpemVvZihmbG9hdCkAbmIxMCA9PSBzaXplb2YoZmxvYXQpAG5iYjEwID09IHNpemVvZihmbG9hdCkAbmIwMCA9PSBzaXplb2YoZmxvYXQpAHNyYzAtPm5iWzBdID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmJ2MCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5icTAgPT0gc2l6ZW9mKGdnbWxfZnAxNl90KQBuYmswID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmIwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmJhMCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5iYzAwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmIwMCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5iYjAwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAJXMgKGNvcHkgb2YgJXMpACFnZ21sX2lzX3ZpZXcodGVuc29yKQAobnVsbCkAZ2dtbF9pc19jb250aWd1b3VzKG1hc2spAG5iMTAgPT0gZ2dtbF90eXBlX3NpemUoc3JjMS0+dHlwZSkAZ2dtbF9pc19xdWFudGl6ZWQoc3JjMC0+dHlwZSkAbmIwMCA9PSBnZ21sX3R5cGVfc2l6ZSh0eXBlKQAlcyAocGVybXV0ZWQpACVzICh0cmFuc3Bvc2VkKQAlcyAocmVzaGFwZWQpAGdnbWxfaXNfY29udGlndW91c19leGNlcHRfZGltXzEoZ3JhZCkAZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBncmFkKQB2aWV3X3NyYyA9PSBOVUxMIHx8IGRhdGFfc2l6ZSArIHZpZXdfb2ZmcyA8PSBnZ21sX25ieXRlcyh2aWV3X3NyYykAcGFyYW1zLT53c2l6ZSA+PSBzaXplb2YoZmxvYXQpICogKG50aCArIG50aCAqIG5jKQBnZ21sX25lbGVtZW50cyhhKSA9PSBnZ21sX25lbGVtZW50cyhiKQBnZ21sX2lzX3NjYWxhcihiKQBnZ21sX2Nhbl9tdWxfbWF0KGEsIGIpAGdnbWxfYXJlX3NhbWVfc2hhcGUoYSwgYikAZ2dtbF9pc19jb250aWd1b3VzKGEpACFnZ21sX2lzX3RyYW5zcG9zZWQoYSkAZ2dtbF9pc19wYWRkZWRfMWQoYSkAZ2dtbF9jYW5fcmVwZWF0X3Jvd3MobWFzaywgYSkAZ2dtbF9jYW5fcmVwZWF0KGIsIGEpAGdnbWxfaXNfY29udGlndW91cyhzcmMxKQBnZ21sX2lzX3NjYWxhcihzcmMxKQBnZ21sX2FyZV9zYW1lX3NoYXBlKHNyYzAsIGRzdCkgJiYgZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBzcmMxKQBnZ21sX2lzX2NvbnRpZ3VvdXMob3B0MCkAZ2dtbF9pc19jb250aWd1b3VzKGRzdCkgJiYgZ2dtbF9pc19jb250aWd1b3VzKHNyYzApAGdnbWxfbmVsZW1lbnRzKGRzdCkgPT0gZ2dtbF9uZWxlbWVudHMoc3JjMCkAb2Zmc2V0ICsgKG5lMTAgPT0gMCA/IDAgOiBuZTEwLTEpKm5iMDAgKyAobmUxMSA9PSAwID8gMCA6IG5lMTEtMSkqbmIwMSArIChuZTEyID09IDAgPyAwIDogbmUxMi0xKSpuYjAyICsgKG5lMTMgPT0gMCA/IDAgOiBuZTEzLTEpKm5iMDMgPCBnZ21sX25ieXRlcyhzcmMwKQBnZ21sX2lzX2NvbnRpZ3VvdXNfZXhjZXB0X2RpbV8xKHNyYzApAGdnbWxfY2FuX3JlcGVhdChkc3QsIHNyYzApACkpKQBvcGVyYXRvcigpACgoKABzcmMxLT50eXBlID09IEdHTUxfVFlQRV9GMzIgJiYgIm9ubHkgZjMyIHNyYzEgc3VwcG9ydGVkIGZvciBub3ciAHRlbnNvci0+YnVmZmVyICE9IE5VTEwgJiYgInRlbnNvciBidWZmZXIgbm90IHNldCIAYWxsb2MtPm5fZnJlZV9ibG9ja3MgPCBNQVhfRlJFRV9CTE9DS1MgJiYgIm91dCBvZiBmcmVlIGJsb2NrcyIAb2Zmc2V0ICsgc2l6ZSA8PSBnZ21sX25ieXRlcyh0ZW5zb3IpICYmICJ0ZW5zb3Igd3JpdGUgb3V0IG9mIGJvdW5kcyIAb2Zmc2V0ICsgc2l6ZSA8PSBnZ21sX25ieXRlcyh0ZW5zb3IpICYmICJ0ZW5zb3IgcmVhZCBvdXQgb2YgYm91bmRzIgBkYXRhICE9IE5VTEwgJiYgImZhaWxlZCB0byBhbGxvY2F0ZSBidWZmZXIiACEibm90IGVub3VnaCBzcGFjZSBpbiB0aGUgYnVmZmVyIgB0ZW5zb3ItPmRhdGEgIT0gTlVMTCAmJiAidGVuc29yIG5vdCBhbGxvY2F0ZWQiAGJhc2UgIT0gTlVMTCAmJiAiYmFja2VuZCBidWZmZXIgYmFzZSBjYW5ub3QgYmUgTlVMTCIAUHVyZSB2aXJ0dWFsIGZ1bmN0aW9uIGNhbGxlZCEAV0FSTklORzogQmVoYXZpb3IgbWF5IGJlIHVuZXhwZWN0ZWQgd2hlbiBhbGxvY2F0aW5nIDAgYnl0ZXMgZm9yIGdnbWxfYWxpZ25lZF9tYWxsb2MhACB8IABBVlggPSAAVlNYID0gAEJMQVMgPSAAT1BFTlZJTk8gPSAATkVPTiA9IABDT1JFTUwgPSAATUVUQUwgPSAAV0FTTV9TSU1EID0gAEYxNkMgPSAARlAxNl9WQSA9IABBUk1fRk1BID0gAENVREEgPSAAU1NTRTMgPSAAQVZYMiA9IABBVlg1MTIgPSAAJXM6IG9wIG5vdCBpbXBsZW1lbnRlZDogACVzOiB0ZW5zb3IgJyVzJyBoYXMgd3Jvbmcgc2l6ZSBpbiBtb2RlbCBmaWxlOiBnb3QgJXp1LCBleHBlY3RlZCAlenUKACVzOiB1c2luZyBkaXN0aWxsZWQgbW9kZWwgLSBmb3JjaW5nIG5vX3RpbWVzdGFtcHMKACVzOiBhZGRpbmcgJWQgZXh0cmEgdG9rZW5zCgAlczogICAgICBtZWwgdGltZSA9ICU4LjJmIG1zCgAlczogICAgdG90YWwgdGltZSA9ICU4LjJmIG1zCgAlczogICAgIGxvYWQgdGltZSA9ICU4LjJmIG1zCgBzeXN0ZW1faW5mbzogbl90aHJlYWRzID0gJWQgLyAlZCB8ICVzCgBXSElTUEVSX0FTU0VSVDogJXM6JWQ6ICVzCgBHR01MX0FTU0VSVDogJXM6JWQ6ICVzCgBbJXMgLS0+ICVzXSAgJXMKACVzOiBvZmZzZXQgJWRtcyBpcyBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBhdWRpbwoAdW5rbm93biB0b2tlbgoAJXM6IGZhaWxlZCB0byBjb21wdXRlIGxvZyBtZWwgc3BlY3Ryb2dyYW0KACVzOiBsb2FkaW5nIG1vZGVsCgAlczogZmFpbGVkIHRvIGxvYWQgbW9kZWwKACVzOiBmYWlsZWQgdG8gZXZhbAoAJXM6ICAgICBmYWxsYmFja3MgPSAlM2QgcCAvICUzZCBoCgAlczogV0FSTiBubyB0ZW5zb3JzIGxvYWRlZCBmcm9tIG1vZGVsIGZpbGUgLSBhc3N1bWluZyBlbXB0eSBtb2RlbCBmb3IgdGVzdGluZwoAJXM6IGVuY29kZXJfYmVnaW5fY2FsbGJhY2sgcmV0dXJuZWQgZmFsc2UgLSBhYm9ydGluZwoAJXM6IHRlbnNvciAnJXMnIGhhcyB3cm9uZyBzaXplIGluIG1vZGVsIGZpbGUKACVzOiB1bmtub3duIHRlbnNvciAnJXMnIGluIG1vZGVsIGZpbGUKACVzOiBubyBzaWduYWwgZGF0YSBhdmFpbGFibGUKACVzOiBmYWlsZWQgdG8gYWxsb2NhdGUgbWVtb3J5IGZvciBrdiBjYWNoZQoAJXM6IGt2X2NhY2hlX2luaXQoKSBmYWlsZWQgZm9yIGNyb3NzLWF0dGVudGlvbiBjYWNoZQoAJXM6IGt2X2NhY2hlX2luaXQoKSBmYWlsZWQgZm9yIHNlbGYtYXR0ZW50aW9uIGNhY2hlCgAlczogZmFpbGVkIHRvIGF1dG8tZGV0ZWN0IGxhbmd1YWdlCgAlczogZmFpbGVkIHRvIGVuY29kZQoAJXM6IGZhaWxlZCB0byBkZWNvZGUKACVzOiBnZ21sX2luaXQoKSBmYWlsZWQKACVzOiBuX3Rva2Vucz0lZCA+IG5fY3R4PSVkCgAlczogRVJST1Igbm90IGFsbCB0ZW5zb3JzIGxvYWRlZCBmcm9tIG1vZGVsIGZpbGUgLSBleHBlY3RlZCAlenUsIGdvdCAlZAoAJXM6IHVua25vd24gbGFuZ3VhZ2UgaWQgJWQKACVzOiB0b28gbWFueSBkZWNvZGVycyByZXF1ZXN0ZWQgKCVkKSwgbWF4ID0gJWQKACVzOiBuX2F1ZGlvX2xheWVyID0gJWQKACVzOiBuX2F1ZGlvX3N0YXRlID0gJWQKACVzOiBuX3RleHRfbGF5ZXIgID0gJWQKACVzOiBuX3RleHRfc3RhdGUgID0gJWQKACVzOiBuX2F1ZGlvX2hlYWQgID0gJWQKACVzOiBuX2F1ZGlvX2N0eCAgID0gJWQKACVzOiBuX3RleHRfaGVhZCAgID0gJWQKACVzOiBuX3RleHRfY3R4ICAg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EBAQEBAAEBAQEBAAEAAQEBAQEBAAABAQEBAQAAAAEBAQEBAQEBAAEBAQEAAQEAAQEBAQEAAQABAQEBAAABAAEBAQEBAQAAAQEBAQABAAABAQEBAQAAAAEBAQEAAAAAAQEBAQEBAQEAAQEBAAEBAQABAQEBAAEBAAEBAQAAAQEAAQEBAQEAAQABAQEAAQABAAEBAQEAAAEAAQEBAAAAAQABAQEBAQEAAAEBAQABAQAAAQEBAQABAAABAQEAAAEAAAEBAQEBAAAAAQEBAAEAAAABAQEBAAAAAAEBAQAAAAAAAQEBAQEBAQEAAQEAAQEBAQABAQEAAQEBAAEBAAABAQEAAQEBAQABAQABAQABAAEBAAEBAQAAAQEAAQEAAAABAQABAQEBAQABAAEBAAEBAAEAAQEBAAEAAQABAQAAAQABAAEBAQEAAAEAAQEAAQAAAQABAQEAAAABAAEBAAAAAAEAAQEBAQEBAAABAQABAQEAAAEBAQABAQAAAQEAAAEBAAABAQEBAAEAAAEBAAEAAQAAAQEBAAABAAABAQAAAAEAAAEBAQEBAAAAAQEAAQEAAAABAQEAAQAAAAEBAAABAAAAAQEBAQAAAAABAQABAAAAAAEBAQAAAAAAAQEAAAAAAAABAQEBAQEBAQABAAEBAQEBAAEBAAEBAQEAAQAAAQEBAQABAQEAAQEBAAEAAQABAQEAAQEAAAEBAQABAAAAAQEBAAEBAQEAAQEAAQABAQABAQABAQABAAEBAAEAAAEAAQEAAQEBAAABAQABAAEAAAEBAAEBAAAAAQEAAQAAAAABAQABAQEBAQABAAEAAQEBAAEAAQEAAQEAAQABAAABAQABAAEBAQABAAEAAQABAAEAAQABAQAAAQABAAEAAAABAAEAAQEBAQAAAQABAAEBAAABAAEBAAEAAAEAAQAAAQAAAQABAQEAAAABAAEAAQAAAAEAAQEAAAAAAQABAAAAAAABAAEBAQEBAQAAAQABAQEBAAABAQABAQEAAAEAAAEBAQAAAQEBAAEBAAABAAEAAQEAAAEBAAABAQAAAQAAAAEBAAABAQEBAAEAAAEAAQEAAQAAAQEAAQABAAABAAABAAEAAAEBAQAAAQAAAQABAAABAAABAQAAAAEAAAEAAAAAAQAAAQEBAQEAAAABAAEBAQAAAAEBAAEBAAAAAQAAAQEAAAABAQEAAQAAAAEAAQABAAAAAQEAAAEAAAABAAAAAQAAAAEBAQEAAAAAAQABAQAAAAABAQABAAAAAAEAAAEAAAAAAQEBAAAAAAABAAEAAAAAAAEBAAAAAAAAAQAAAAAAAAABAQEBAQEBAQAAAQEBAQEBAAEAAQEBAQEAAAABAQEBAQABAQABAQEBAAABAAEBAQEAAQAAAQEBAQAAAAABAQEBAAEBAQABAQEAAAEBAAEBAQABAAEAAQEBAAAAAQABAQEAAQEAAAEBAQAAAQAAAQEBAAEAAAABAQEAAAAAAAEBAQABAQEBAAEBAAABAQEAAQEAAQABAQABAQAAAAEBAAEBAAEBAAEAAQEAAAEAAQABAQABAAABAAEBAAAAAAEAAQEAAQEBAAABAQAAAQEAAAEBAAEAAQAAAQEAAAABAAABAQABAQAAAAEBAAABAAAAAQEAAQAAAAABAQAAAAAAAAEBAAEBAQEBAAEAAAEBAQEAAQABAAEBAQABAAAAAQEBAAEAAQEAAQEAAQAAAQABAQABAAEAAAEBAAEAAAAAAQEAAQABAQEAAQABAAABAQABAAEAAQABAAEAAQAAAAEAAQABAAEBAAABAAEAAAEAAAEAAQABAAAAAQABAAAAAAABAAEAAQEBAQAAAQAAAQEBAAABAAEAAQEAAAEAAAABAQAAAQABAQABAAABAAABAAEAAAEAAQAAAQAAAQAAAAABAAABAAEBAQAAAAEAAAEBAAAAAQABAAEAAAABAAAAAQAAAAEAAQEAAAAAAQAAAQAAAAABAAEAAAAAAAEAAAAAAAAAAQABAQEBAQEAAAABAQEBAQAAAQABAQEBAAAAAAEBAQEAAAEBAAEBAQAAAAEAAQEBAAABAAABAQEAAAAAAAEBAQAAAQEBAAEBAAAAAQEAAQEAAAEAAQABAQAAAAABAAEBAAABAQAAAQEAAAABAAABAQAAAQAAAAEBAAAAAAAAAQEAAAEBAQEAAQAAAAEBAQABAAABAAEBAAEAAAAAAQEAAQAAAQEAAQABAAAAAQABAAEAAAEAAAEAAQAAAAAAAQABAAABAQEAAAEAAAABAQAAAQAAAQABAAABAAAAAAEAAAEAAAEBAAAAAQAAAAEAAAABAAABAAAAAAEAAAAAAAAAAQAAAQEBAQEAAAAAAQEBAQAAAAEAAQEBAAAAAAABAQEAAAABAQABAQAAAAABAAEBAAAAAQAAAQEAAAAAAAABAQAAAAEBAQABAAAAAAEBAAEAAAABAAEAAQAAAAAAAQABAAAAAQEAAAEAAAAAAQAAAQAAAAEAAAABAAAAAAAAAAEAAAABAQEBAAAAAAABAQEAAAAAAQABAQAAAAAAAAEBAAAAAAEBAAEAAAAAAAEAAQAAAAABAAABAAAAAAAAAAEAAAAAAQEBAAAAAAAAAQEAAAAAAAEAAQAAAAAAAAABAAAAAAABAQAAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAEBAAAAAAAAAAABAAAAAAABAAEAAAAAAAABAQAAAAAAAQEBAAAAAAAAAAABAAAAAAEAAAEAAAAAAAEAAQAAAAABAQABAAAAAAAAAQEAAAAAAQABAQAAAAAAAQEBAAAAAAEBAQEAAAAAAAAAAAEAAAABAAAAAQAAAAABAAABAAAAAQEAAAEAAAAAAAEAAQAAAAEAAQABAAAAAAEBAAEAAAABAQEAAQAAAAAAAAEBAAAAAQAAAQEAAAAAAQABAQAAAAEBAAEBAAAAAAABAQEAAAABAAEBAQAAAAABAQEBAAAAAQEBAQEAAAAAAAAAAAEAAAEAAAAAAQAAAAEAAAABAAABAQAAAAEAAAAAAQAAAQAAAQABAAABAAAAAQEAAAEAAAEBAQAAAQAAAAAAAQABAAABAAABAAEAAAABAAEAAQAAAQEAAQABAAAAAAEBAAEAAAEAAQEAAQAAAAEBAQABAAABAQEBAAEAAAAAAAABAQAAAQAAAAEBAAAAAQAAAQEAAAEBAAABAQAAAAABAAEBAAABAAEAAQEAAAABAQABAQAAAQEBAAEBAAAAAAABAQEAAAEAAAEBAQAAAAEAAQEBAAABAQABAQEAAAAAAQEBAQAAAQABAQEBAAAAAQEBAQEAAAEBAQEBAQAAAAAAAAAAAQABAAAAAAABAAABAAAAAAEAAQEAAAAAAQAAAAEAAAABAAEAAQAAAAEAAAEBAAAAAQABAQEAAAABAAAAAAEAAAEAAQAAAQAAAQAAAQABAAABAAEBAAEAAAEAAAABAQAAAQABAAEBAAABAAABAQEAAAEAAQEBAQAAAQAAAAAAAQABAAEAAAABAAEAAAEAAAEAAQABAQAAAQABAAAAAQABAAEAAQABAAEAAQAAAQEAAQABAAEBAQABAAEAAAAAAQEAAQABAAABAQABAAABAAEBAAEAAQEAAQEAAQAAAAEBAQABAAEAAQEBAAEAAAEBAQEAAQABAQEBAQABAAAAAAAAAQEAAQAAAAABAQAAAQAAAAEBAAEBAAAAAQEAAAABAAABAQABAAEAAAEBAAABAQAAAQEAAQEBAAABAQAAAAABAAEBAAEAAAEAAQEAAAEAAQABAQABAQABAAEBAAAAAQEAAQEAAQABAQABAQAAAQEBAAEBAAEBAQEAAQEAAAAAAAEBAQABAAAAAQEBAAABAAABAQEAAQEAAAEBAQAAAAEAAQEBAAEAAQABAQEAAAEBAAEBAQABAQEAAQEBAAAAAAEBAQEAAQAAAQEBAQAAAQABAQEBAAEBAAEBAQEAAAABAQEBAQABAAEBAQEBAAABAQEBAQEAAQEBAQEBAQAAAAAAAAAAAQEAAAAAAAABAAEAAAAAAAEBAQAAAAAAAQAAAQAAAAABAQABAAAAAAEAAQEAAAAAAQEBAQAAAAABAAAAAQAAAAEBAAABAAAAAQABAAEAAAABAQEAAQAAAAEAAAEBAAAAAQEAAQEAAAABAAEBAQAAAAEBAQEBAAAAAQAAAAABAAABAQAAAAEAAAEAAQAAAQAAAQEBAAABAAABAAABAAEAAAEBAAEAAQAAAQABAQABAAABAQEBAAEAAAEAAAABAQAAAQEAAAEBAAABAAEAAQEAAAEBAQABAQAAAQAAAQEBAAABAQABAQEAAAEAAQEBAQAAAQEBAQEBAAABAAAAAAABAAEBAAAAAAEAAQABAAAAAQABAQEAAAABAAEAAAEAAAEAAQEAAQAAAQABAAEBAAABAAEBAQEAAAEAAQAAAAEAAQABAQAAAQABAAEAAQABAAEAAQEBAAEAAQABAAABAQABAAEBAAEBAAEAAQABAQEAAQABAQEBAQABAAEAAAAAAQEAAQEAAAABAQABAAEAAAEBAAEBAQAAAQEAAQAAAQABAQABAQABAAEBAAEAAQEAAQEAAQEBAQABAQABAAAAAQEBAAEBAAABAQEAAQABAAEBAQABAQEAAQEBAAEAAAEBAQEAAQEAAQEBAQABAAEBAQEBAAEBAQEBAQEAAQAAAAAAAAEBAQAAAAAAAQEAAQAAAAABAQEBAAAAAAEBAAABAAAAAQEBAAEAAA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AAAAXwAAAGAAAABhAAAATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE5TXzEzX19lbXB0eV9zdGF0ZUljRUVOU18xMHNoYXJlZF9wdHJJUzJfRTI3X19zaGFyZWRfcHRyX2RlZmF1bHRfZGVsZXRlSVMyX1MyX0VFTlNfOWFsbG9jYXRvcklTMl9FRUVFAAAAAAjaAABYUwAAiNAAAE5TdDNfXzIxMHNoYXJlZF9wdHJJTlNfMTNfX2VtcHR5X3N0YXRlSWNFRUUyN19fc2hhcmVkX3B0cl9kZWZhdWx0X2RlbGV0ZUlTMl9TMl9FRQAAAAAAAADIVAAAYgAAAGMAAABkAAAAXAAAAE5TdDNfXzIxM19fZW1wdHlfc3RhdGVJY0VFAE5TdDNfXzIxNl9fb3duc19vbmVfc3RhdGVJY0VFAE5TdDNfXzIxNV9faGFzX29uZV9zdGF0ZUljRUUAAAAI2gAAkVQAAChTAAAI2gAAc1QAALBUAAAI2gAAWFQAALxUAAAAAAAAvFQAAGIAAABlAAAAZgAAAFwAAAAAAAAAKFUAAGIAAABnAAAAaAAAAFwAAABOU3QzX18yMjBfX2xfYW5jaG9yX211bHRpbGluZUljRUUAAAAI2gAABFUAALxUAAAAAAAAcFUAAGIAAABpAAAAagAAAFwAAABOU3QzX18yMjBfX3JfYW5jaG9yX211bHRpbGluZUljRUUAAAAI2gAATFUAALxUAAAAAAAAyFUAAGsAAABsAAAAbQAAAFwAAABOU3QzX18yMTVfX3dvcmRfYm91bmRhcnlJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAACNoAAJRVAAC8VAAAAAAAABxWAABuAAAAbwAAAHAAAABcAAAATlN0M19fMjExX19sb29rYWhlYWRJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAACNoAAOxVAAC8VAAAAAAAAGhWAABiAAAAcQAAAHIAAABcAAAATlN0M19fMjIzX19tYXRjaF9hbnlfYnV0X25ld2xpbmVJY0VFAAAAAAjaAABAVgAAvFQAAAAAAADEVgAAcwAAAHQAAAB1AAAAXAAAAE5TdDNfXzIxOF9fbWF0Y2hfY2hhcl9pY2FzZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAAACNoAAIxWAAC8VAAAAAAAACBXAAB2AAAAdwAAAHgAAABcAAAATlN0M19fMjIwX19tYXRjaF9jaGFyX2NvbGxhdGVJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAI2gAA6FYAALxUAAAAAAAAYFcAAGIAAAB5AAAAegAAAFwAAABOU3QzX18yMTJfX21hdGNoX2NoYXJJY0VFAAAACNoAAERXAAC8VAAAAAAAALhXAAB7AAAAfAAAAH0AAABcAAAATlN0M19fMjE2X19iYWNrX3JlZl9pY2FzZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAjaAACEVwAAvFQAAAAAAAAUWAAAfgAAAH8AAACAAAAAXAAAAE5TdDNfXzIxOF9fYmFja19yZWZfY29sbGF0ZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAAACNoAANxXAAC8VAAAAAAAAFBYAABiAAAAgQAAAIIAAABcAAAATlN0M19fMjEwX19iYWNrX3JlZkljRUUACNoAADhYAAC8VAAAAAAAAKxYAACDAAAAhAAAAIUAAABcAAAATlN0M19fMjIwX19icmFja2V0X2V4cHJlc3Npb25JY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAI2gAAdFgAALxUAAAAAAAA/FgAAGIAAACGAAAAhwAAAFwAAABOU3QzX18yMjhfX2JlZ2luX21hcmtlZF9zdWJleHByZXNzaW9uSWNFRQAAAAjaAADQWAAAvFQAAAAAAABIWQAAYgAAAIgAAACJAAAAXAAAAE5TdDNfXzIyNl9fZW5kX21hcmtlZF9zdWJleHByZXNzaW9uSWNFRQAI2gAAIFkAALxUAAAAAAAArFkAAIoAAACLAAAAjAAAAI0AAABOU3QzX18yNl9fbG9vcEljRUUATlN0M19fMjE3X19vd25zX3R3b19zdGF0ZXNJY0VFAAAACNoAAH9ZAAC8VAAACNoAAGxZAACgWQAAAAAAAKBZAACKAAAAjgAAAGYAAABcAAAAAAAAAAhaAABZAAAAjwAAAJAAAABcAAAATlN0M19fMjE3X19yZXBlYXRfb25lX2xvb3BJY0VFAAAI2gAA6FkAALBUAAAAAAAASFoAAIoAAACRAAAAkgAAAJMAAABOU3QzX18yMTFfX2FsdGVybmF0ZUljRUUAAAAACNoAACxaAACgWQAAAAAAAJBaAABZAAAAlAAAAJUAAABcAAAATlN0M19fMjIxX19lbXB0eV9ub25fb3duX3N0YXRlSWNFRQAACNoAAGxaAACwVAAAAAAAANBaAABiAAAAlgAAAJcAAABcAAAATlN0M19fMjExX19tYXRjaF9hbnlJY0VFAAAAAAjaAAC0WgAAvFQAAAAAAACcWwAAmAAAAJkAAACaAAAAmwAAAJwAAACdAAAAngAAAJ8AAACgAAAATlN0M19fMjEwX19mdW5jdGlvbjZfX2Z1bmNJWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzBOU185YWxsb2NhdG9ySVMyX0VFRlAxMWdnbWxfY2dyYXBodkVFRQBOU3QzX18yMTBfX2Z1bmN0aW9uNl9fYmFzZUlGUDExZ2dtbF9jZ3JhcGh2RUVFAADg2QAAZFsAAAjaAAAIWwAAlFsAAFoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8wAADg2QAAqFsAAAAAAABUXAAAmAAAAKEAAACiAAAAowAAAKQAAAClAAAApgAAAKcAAACoAAAATlN0M19fMjEwX19mdW5jdGlvbjZfX2Z1bmNJWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzFOU185YWxsb2NhdG9ySVMyX0VFRlAxMWdnbWxfY2dyYXBodkVFRQAI2gAA+FsAAJRbAABaMTh3aGlzcGVyX2luaXRfc3RhdGVFMyRfMQAA4NkAAGBcAAAAAAAADF0AAJgAAACpAAAAqgAAAKsAAACsAAAArQAAAK4AAACvAAAAsAAAAE5TdDNfXzIxMF9fZnVuY3Rpb242X19mdW5jSVoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8yTlNfOWFsbG9jYXRvcklTMl9FRUZQMTFnZ21sX2NncmFwaHZFRUUACNoAALBcAACUWwAAWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzIAAODZAAAYXQAAAAAAAMRdAACYAAAAsQAAALIAAACzAAAAtAAAALUAAAC2AAAAtwAAALgAAABOU3QzX18yMTBfX2Z1bmN0aW9uNl9fZnVuY0laMTh3aGlzcGVyX2luaXRfc3RhdGVFMyRfM05TXzlhbGxvY2F0b3JJUzJfRUVGUDExZ2dtbF9jZ3JhcGh2RUVFAAjaAABoXQAAlFsAAFoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8zAADg2QAA0F0AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0loTlNfMTFjaGFyX3RyYWl0c0loRUVOU185YWxsb2NhdG9ySWhFRUVFAADg2QAA9F0AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0l3TlNfMTFjaGFyX3RyYWl0c0l3RUVOU185YWxsb2NhdG9ySXdFRUVFAADg2QAAPF4AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0lEc05TXzExY2hhcl90cmFpdHNJRHNFRU5TXzlhbGxvY2F0b3JJRHNFRUVFAAAA4NkAAIReAABOU3QzX18yMTJiYXNpY19zdHJpbmdJRGlOU18xMWNoYXJfdHJhaXRzSURpRUVOU185YWxsb2NhdG9ySURpRUVFRQAAAODZAADQXgAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJY0VFAADg2QAAHF8AAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWFFRQAA4NkAAERfAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0loRUUAAODZAABsXwAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJc0VFAADg2QAAlF8AAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXRFRQAA4NkAALxfAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lpRUUAAODZAADkXwAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJakVFAADg2QAADGAAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWxFRQAA4NkAADRgAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0ltRUUAAODZAABcYAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJeEVFAADg2QAAhGAAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXlFRQAA4NkAAKxgAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lmRUUAAODZAADUYAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZEVFAADg2QAA/GAAAAAAAAAAAAAAAAAAAAMAAAAEAAAABAAAAAYAAACD+aIARE5uAPwpFQDRVycA3TT1AGLbwAA8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SWNFRUVFAAAAAODZAADEpAAATlN0M19fMjEzYmFzaWNfaXN0cmVhbUljTlNfMTFjaGFyX3RyYWl0c0ljRUVFRQAAZNoAAAClAAAAAAAAAQAAALikAAAD9P//bAAAAAAAAADYpQAA7wAAAPAAAACU////lP///9ilAADxAAAA8gAAAFSlAACMpQAAoKUAAGilAABsAAAAAAAAADClAADhAAAA4gAAAJT///+U////MKUAAOMAAADkAAAATlN0M19fMjE0YmFzaWNfaWZzdHJlYW1JY05TXzExY2hhcl90cmFpdHNJY0VFRUUACNoAAKilAAAwpQAATlN0M19fMjEzYmFzaWNfZmlsZWJ1ZkljTlNfMTFjaGFyX3RyYWl0c0ljRUVFRQAACNoAAOSlAAD4pAAAAAAAAESmAADzAAAA9AAAAE5TdDNfXzI4aW9zX2Jhc2VFAAAA4NkAADCmAAAAAAAA0XSeAFedvSqAcFIP//8+JwoAAABkAAAA6AMAABAnAACghgEAQEIPAICWmAAA4fUFGAAAADUAAABxAAAAa////877//+Sv///AAAAAAAAAAD/////////////////////////////////////////////////////////////////AAECAwQFBgcICf////////8KCwwNDg8QERITFBUWFxgZGhscHR4fICEiI////////woLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgQHAwYFAAAAAAAAAAIAAMADAADABAAAwAUAAMAGAADABwAAwAgAAMAJAADACgAAwAsAAMAMAADADQAAwA4AAMAPAADAEAAAwBEAAMASAADAEwAAwBQAAMAVAADAFgAAwBcAAMAYAADAGQAAwBoAAMAbAADAHAAAwB0AAMAeAADAHwAAwAAAALMBAADDAgAAwwMAAMMEAADDBQAAwwYAAMMHAADDCAAAwwkAAMMKAADDCwAAwwwAAMMNAADTDgAAww8AAMMAAAy7AQAMwwIA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ODY4Nzg4ODk5MDkxOTI5Mzk0OTU5Njk3OTg5OQAAAAAAAAAAAv8ABGQAIAAABP//BgABAAEAAQD//wH/Af//////Af8B/wH/Af8B/wH/Af8B//////8K/yAA//8D/wH/BP8eAAABBf//////YwAACGMA6AMCAAAA//////8AAAAB/wH//////////////wAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAB/wH//////wABIAAEAIAAAAj//wH/Af////////8B/wb/B/8I/wn//////7wCvAIBAP//AQABAP//AAD//////////wAAAAAAAAAAAAAAAAAAAAAUAXj//wEACv///////////wH/Af8AAAAAAAAB/wH/Af8AAAAAAAAAAAAAAAAAAAAAAAAB/wAAAAAAAAH/Af8BAAAAAQAAAAH//////wAAAAAB////AAAAAP////////////8oAAr//////wEACv////8A//////////8BvggB/wH///8BAP//////////////////Cv//////DP8N/04xMF9fY3h4YWJpdjExNl9fc2hpbV90eXBlX2luZm9FAAAI2gAAFtgAACzcAABOMTBfX2N4eGFiaXYxMTdfX2NsYXNzX3R5cGVfaW5mb0UAAAAI2gAARNgAADjYAABOMTBfX2N4eGFiaXYxMTdfX3BiYXNlX3R5cGVfaW5mb0UAAAAI2gAAdNgAADjYAABOMTBfX2N4eGFiaXYxMTlfX3BvaW50ZXJfdHlwZV9pbmZvRQAI2gAApNgAAJjYAAAAAAAAGNkAAP8BAAAAAgAAAQIAAAICAAADAgAATjEwX19jeHhhYml2MTIzX19mdW5kYW1lbnRhbF90eXBlX2luZm9FAAjaAADw2AAAONgAAHYAAADc2AAAJNkAAGIAAADc2AAAMNkAAGMAAADc2AAAPNkAAGgAAADc2AAASNkAAGEAAADc2AAAVNkAAHMAAADc2AAAYNkAAHQAAADc2AAAbNkAAGkAAADc2AAAeNkAAGoAAADc2AAAhNkAAGwAAADc2AAAkNkAAG0AAADc2AAAnNkAAHgAAADc2AAAqNkAAHkAAADc2AAAtNkAAGYAAADc2AAAwNkAAGQAAADc2AAAzNkAAAAAAABo2AAA/wEAAAQCAAABAgAAAgIAAAUCAAAGAgAABwIAAAgCAAAAAAAAUNoAAP8BAAAJAgAAAQIAAAICAAAFAgAACgIAAAsCAAAMAgAATjEwX19jeHhhYml2MTIwX19zaV9jbGFzc190eXBlX2luZm9FAAAAAAjaAAAo2gAAaNgAAAAAAACs2gAA/wEAAA0CAAABAgAAAgIAAAUCAAAOAgAADwIAABACAABOMTBfX2N4eGFiaXYxMjFfX3ZtaV9jbGFzc190eXBlX2luZm9FAAAACNoAAITaAABo2AAAAAAAABzbAAAIAAAAEQIAABICAAAAAAAARNsAAAgAAAATAgAAFAIAAAAAAAAE2wAACAAAABUCAAAWAgAAU3Q5ZXhjZXB0aW9uAAAAAODZAAD02gAAU3Q5YmFkX2FsbG9jAAAAAAjaAAAM2wAABNsAAFN0MjBiYWRfYXJyYXlfbmV3X2xlbmd0aAAAAAAI2gAAKNsAABzbAAAAAAAAiNsAAAcAAAAXAgAAGAIAAAAAAAAQ3AAAGQIAABoCAAD8AQAAU3QxMWxvZ2ljX2Vycm9yAAjaAAB42wAABNsAAAAAAAC82wAABwAAABsCAAAYAgAAU3QxMmxlbmd0aF9lcnJvcgAAAAAI2gAAqNsAAIjbAAAAAAAA8NsAAAcAAAAcAgAAGAIAAFN0MTJvdXRfb2ZfcmFuZ2UAAAAACNoAANzbAACI2wAAU3QxM3J1bnRpbWVfZXJyb3IAAAAI2gAA/NsAAATbAABTdDl0eXBlX2luZm8AAAAA4NkAABzcAAABFT0AAAA+AAAAAAAAAD8AAAAAAAAAWAFoUNwAAFDcAAAAAAEAAAIAAAAAAAAFAAAAAAAAAAAAAAC9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7AAAAugAAAOA9DQAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAA//////////8BWZjcAAAAAAAABQAAAAAAAAAAAAAAywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuwAAAMwAAADoPQ0AAAQAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAP////8KAQww3QAAwEwOAP4BAAA=";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;wasmExports=exports;registerTLSInit(wasmExports["_"]);wasmTable=wasmExports["X"];addOnInit(wasmExports["W"]);wasmModule=module;removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"],result["module"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var terminateWorker=worker=>{worker.terminate();worker.onmessage=e=>{}};var killThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];delete PThread.pthreads[pthread_ptr];terminateWorker(worker);__emscripten_thread_free_data(pthread_ptr);PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker),1);worker.pthread_ptr=0};var cancelThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];worker.postMessage({"cmd":"cancel"})};var cleanupThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];assert(worker);PThread.returnWorkerToPool(worker)};var spawnThread=threadParams=>{var worker=PThread.getNewWorker();if(!worker){return 6}PThread.runningWorkers.push(worker);PThread.pthreads[threadParams.pthread_ptr]=worker;worker.pthread_ptr=threadParams.pthread_ptr;var msg={"cmd":"run","start_routine":threadParams.startRoutine,"arg":threadParams.arg,"pthread_ptr":threadParams.pthread_ptr};if(ENVIRONMENT_IS_NODE){worker.unref()}worker.postMessage(msg,threadParams.transferList);return 0};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>(view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))),view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.buffer instanceof SharedArrayBuffer?heapOrArray.slice(idx,endPtr):heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val}},isRead:{get(){return(this.flags&2097155)!==1}},isWrite:{get(){return(this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val}},position:{get(){return this.shared.position},set(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError(){if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,GROWABLE_HEAP_I8(),ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(GROWABLE_HEAP_U8(),ptr,maxBytesToRead):"";var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}GROWABLE_HEAP_I32()[buf>>2]=stat.dev;GROWABLE_HEAP_I32()[buf+4>>2]=stat.mode;GROWABLE_HEAP_U32()[buf+8>>2]=stat.nlink;GROWABLE_HEAP_I32()[buf+12>>2]=stat.uid;GROWABLE_HEAP_I32()[buf+16>>2]=stat.gid;GROWABLE_HEAP_I32()[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+24>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+28>>2]=tempI64[1];GROWABLE_HEAP_I32()[buf+32>>2]=4096;GROWABLE_HEAP_I32()[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+40>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+44>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+56>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+60>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+72>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+76>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+88>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=GROWABLE_HEAP_U8().slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get(){var ret=GROWABLE_HEAP_I32()[SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};function _proc_exit(code){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(0,1,code);EXITSTATUS=code;if(!keepRuntimeAlive()){PThread.terminateAllThreads();if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}var exitJS=(status,implicit)=>{EXITSTATUS=status;if(ENVIRONMENT_IS_PTHREAD){exitOnMainThread(status);throw"unwind"}_proc_exit(status)};var _exit=exitJS;var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var PThread={unusedWorkers:[],runningWorkers:[],tlsInitFunctions:[],pthreads:{},init(){if(ENVIRONMENT_IS_PTHREAD){PThread.initWorker()}else{PThread.initMainThread()}},initMainThread(){var pthreadPoolSize=8;while(pthreadPoolSize--){PThread.allocateUnusedWorker()}addOnPreRun(()=>{addRunDependency("loading-workers");PThread.loadWasmModuleToAllWorkers(()=>removeRunDependency("loading-workers"))})},initWorker(){noExitRuntime=false},setExitStatus:status=>{EXITSTATUS=status},terminateAllThreads__deps:["$terminateWorker"],terminateAllThreads:()=>{for(var worker of PThread.runningWorkers){terminateWorker(worker)}for(var worker of PThread.unusedWorkers){terminateWorker(worker)}PThread.unusedWorkers=[];PThread.runningWorkers=[];PThread.pthreads=[]},returnWorkerToPool:worker=>{var pthread_ptr=worker.pthread_ptr;delete PThread.pthreads[pthread_ptr];PThread.unusedWorkers.push(worker);PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker),1);worker.pthread_ptr=0;__emscripten_thread_free_data(pthread_ptr)},receiveObjectTransfer(data){},threadInitTLS(){PThread.tlsInitFunctions.forEach(f=>f())},loadWasmModuleToWorker:worker=>new Promise(onFinishedLoading=>{worker.onmessage=e=>{var d=e["data"];var cmd=d["cmd"];if(d["targetThread"]&&d["targetThread"]!=_pthread_self()){var targetWorker=PThread.pthreads[d["targetThread"]];if(targetWorker){targetWorker.postMessage(d,d["transferList"])}else{err(`Internal error! Worker sent a message "${cmd}" to target pthread ${d["targetThread"]}, but that thread no longer exists!`)}return}if(cmd==="checkMailbox"){checkMailbox()}else if(cmd==="spawnThread"){spawnThread(d)}else if(cmd==="cleanupThread"){cleanupThread(d["thread"])}else if(cmd==="killThread"){killThread(d["thread"])}else if(cmd==="cancelThread"){cancelThread(d["thread"])}else if(cmd==="loaded"){worker.loaded=true;if(ENVIRONMENT_IS_NODE&&!worker.pthread_ptr){worker.unref()}onFinishedLoading(worker)}else if(cmd==="alert"){alert(`Thread ${d["threadId"]}: ${d["text"]}`)}else if(d.target==="setimmediate"){worker.postMessage(d)}else if(cmd==="callHandler"){Module[d["handler"]](...d["args"])}else if(cmd){err(`worker sent an unknown command ${cmd}`)}};worker.onerror=e=>{var message="worker sent an error!";err(`${message} ${e.filename}:${e.lineno}: ${e.message}`);throw e};if(ENVIRONMENT_IS_NODE){worker.on("message",data=>worker.onmessage({data:data}));worker.on("error",e=>worker.onerror(e))}var handlers=[];var knownHandlers=["onExit","onAbort","print","printErr"];for(var handler of knownHandlers){if(Module.hasOwnProperty(handler)){handlers.push(handler)}}worker.postMessage({"cmd":"load","handlers":handlers,"urlOrBlob":Module["mainScriptUrlOrBlob"]||_scriptDir,"wasmMemory":wasmMemory,"wasmModule":wasmModule})}),loadWasmModuleToAllWorkers(onMaybeReady){if(ENVIRONMENT_IS_PTHREAD){return onMaybeReady()}let pthreadPoolReady=Promise.all(PThread.unusedWorkers.map(PThread.loadWasmModuleToWorker));pthreadPoolReady.then(onMaybeReady)},allocateUnusedWorker(){var worker;var pthreadMainJs=locateFile("libwhisper.worker.js");worker=new Worker(pthreadMainJs);PThread.unusedWorkers.push(worker)},getNewWorker(){if(PThread.unusedWorkers.length==0){PThread.allocateUnusedWorker();PThread.loadWasmModuleToWorker(PThread.unusedWorkers[0])}return PThread.unusedWorkers.pop()}};Module["PThread"]=PThread;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var establishStackSpace=()=>{var pthread_ptr=_pthread_self();var stackHigh=GROWABLE_HEAP_I32()[pthread_ptr+52>>2];var stackSize=GROWABLE_HEAP_I32()[pthread_ptr+56>>2];var stackLow=stackHigh-stackSize;_emscripten_stack_set_limits(stackHigh,stackLow);stackRestore(stackHigh)};Module["establishStackSpace"]=establishStackSpace;function exitOnMainThread(returnCode){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(1,0,returnCode);_exit(returnCode)}var wasmTableMirror=[];var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var invokeEntryPoint=(ptr,arg)=>{var result=getWasmTableEntry(ptr)(arg);function finish(result){if(keepRuntimeAlive()){PThread.setExitStatus(result)}else{__emscripten_thread_exit(result)}}finish(result)};Module["invokeEntryPoint"]=invokeEntryPoint;var registerTLSInit=tlsInitFunc=>{PThread.tlsInitFunctions.push(tlsInitFunc)};function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){GROWABLE_HEAP_U32()[this.ptr+4>>2]=type};this.get_type=function(){return GROWABLE_HEAP_U32()[this.ptr+4>>2]};this.set_destructor=function(destructor){GROWABLE_HEAP_U32()[this.ptr+8>>2]=destructor};this.get_destructor=function(){return GROWABLE_HEAP_U32()[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;GROWABLE_HEAP_I8()[this.ptr+12>>0]=caught};this.get_caught=function(){return GROWABLE_HEAP_I8()[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;GROWABLE_HEAP_I8()[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return GROWABLE_HEAP_I8()[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){GROWABLE_HEAP_U32()[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return GROWABLE_HEAP_U32()[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return GROWABLE_HEAP_U32()[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var ___emscripten_init_main_thread_js=tb=>{__emscripten_thread_init(tb,!ENVIRONMENT_IS_WORKER,1,!ENVIRONMENT_IS_WEB,65536,false);PThread.threadInitTLS()};var ___emscripten_thread_cleanup=thread=>{if(!ENVIRONMENT_IS_PTHREAD)cleanupThread(thread);else postMessage({"cmd":"cleanupThread","thread":thread})};function pthreadCreateProxied(pthread_ptr,attr,startRoutine,arg){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(2,1,pthread_ptr,attr,startRoutine,arg);return ___pthread_create_js(pthread_ptr,attr,startRoutine,arg)}var ___pthread_create_js=(pthread_ptr,attr,startRoutine,arg)=>{if(typeof SharedArrayBuffer=="undefined"){err("Current environment does not support SharedArrayBuffer, pthreads are not available!");return 6}var transferList=[];var error=0;if(ENVIRONMENT_IS_PTHREAD&&(transferList.length===0||error)){return pthreadCreateProxied(pthread_ptr,attr,startRoutine,arg)}if(error)return error;var threadParams={startRoutine:startRoutine,pthread_ptr:pthread_ptr,arg:arg,transferList:transferList};if(ENVIRONMENT_IS_PTHREAD){threadParams.cmd="spawnThread";postMessage(threadParams,transferList);return 0}return spawnThread(threadParams)};var setErrNo=value=>{GROWABLE_HEAP_I32()[___errno_location()>>2]=value;return value};function ___syscall_fcntl64(fd,cmd,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(3,1,fd,cmd,varargs);SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.getp();var offset=0;GROWABLE_HEAP_I16()[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(4,1,fd,op,varargs);SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=SYSCALLS.getp();GROWABLE_HEAP_I32()[argp>>2]=termios.c_iflag||0;GROWABLE_HEAP_I32()[argp+4>>2]=termios.c_oflag||0;GROWABLE_HEAP_I32()[argp+8>>2]=termios.c_cflag||0;GROWABLE_HEAP_I32()[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){GROWABLE_HEAP_I8()[argp+i+17>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=SYSCALLS.getp();var c_iflag=GROWABLE_HEAP_I32()[argp>>2];var c_oflag=GROWABLE_HEAP_I32()[argp+4>>2];var c_cflag=GROWABLE_HEAP_I32()[argp+8>>2];var c_lflag=GROWABLE_HEAP_I32()[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(GROWABLE_HEAP_I8()[argp+i+17>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.getp();GROWABLE_HEAP_I32()[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.getp();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=SYSCALLS.getp();GROWABLE_HEAP_I16()[argp>>1]=winsize[0];GROWABLE_HEAP_I16()[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(5,1,dirfd,path,flags,varargs);SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes=undefined;var readLatin1String=ptr=>{var ret="";var c=ptr;while(GROWABLE_HEAP_U8()[c]){ret+=embind_charCodes[GROWABLE_HEAP_U8()[c++]]}return ret};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError=undefined;var throwBindingError=message=>{throw new BindingError(message)};var InternalError=undefined;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":function(pointer){return this["fromWireType"](GROWABLE_HEAP_U8()[pointer])},destructorFunction:null})};function handleAllocatorInit(){Object.assign(HandleAllocator.prototype,{get(id){return this.allocated[id]},has(id){return this.allocated[id]!==undefined},allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id},free(id){this.allocated[id]=undefined;this.freelist.push(id)}})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[]}var emval_handles=new HandleAllocator;var __emval_decref=handle=>{if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}};var count_emval_handles=()=>{var count=0;for(var i=emval_handles.reserved;i{emval_handles.allocated.push({value:undefined},{value:null},{value:true},{value:false});emval_handles.reserved=emval_handles.allocated.length;Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](GROWABLE_HEAP_I32()[pointer>>2])}var __embind_register_emval=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":(destructors,value)=>Emval.toHandle(value),"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](GROWABLE_HEAP_F32()[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](GROWABLE_HEAP_F64()[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":value=>value,"toWireType":(destructors,value)=>value,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":floatReadValueFromPointer(name,size),destructorFunction:null})};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function createNamedFunction(name,body){name=makeLegalFunctionName(name);return{[name]:function(){return body.apply(this,arguments)}}[name]}function newFunc(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError(`new_ called with constructor type ${typeof constructor} which is not a function`)}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc,isAsync){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns||isAsync?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${arguments.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{var f=Module["dynCall_"+sig];return args&&args.length?f.apply(null,[ptr].concat(args)):f.call(null,ptr)};var dynCall=(sig,ptr,args)=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr).apply(null,args);return rtn};var getDynCaller=(sig,ptr)=>{var argCache=[];return function(){argCache.length=0;Object.assign(argCache,arguments);return dynCall(sig,ptr,argCache)}};var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError=undefined;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>GROWABLE_HEAP_I8()[pointer>>0]:pointer=>GROWABLE_HEAP_U8()[pointer>>0];case 2:return signed?pointer=>GROWABLE_HEAP_I16()[pointer>>1]:pointer=>GROWABLE_HEAP_U16()[pointer>>1];case 4:return signed?pointer=>GROWABLE_HEAP_I32()[pointer>>2]:pointer=>GROWABLE_HEAP_U32()[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=GROWABLE_HEAP_U32()[handle>>2];var data=GROWABLE_HEAP_U32()[handle+4>>2];return new TA(GROWABLE_HEAP_I8().buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})};function readPointer(pointer){return this["fromWireType"](GROWABLE_HEAP_U32()[pointer>>2])}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,GROWABLE_HEAP_U8(),outPtr,maxBytesToWrite);var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":value=>{var length=GROWABLE_HEAP_U32()[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||GROWABLE_HEAP_U8()[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i{if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var length;var valueIsOfTypeString=typeof value=="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){length=lengthBytesUTF8(value)}else{length=value.length}var base=_malloc(4+length+1);var ptr=base+4;GROWABLE_HEAP_U32()[base>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}GROWABLE_HEAP_U8()[ptr+i]=charCode}}else{for(var i=0;i_free(ptr)})};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&GROWABLE_HEAP_U16()[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(GROWABLE_HEAP_U8().slice(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=GROWABLE_HEAP_I16()[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}GROWABLE_HEAP_I16()[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=GROWABLE_HEAP_I32()[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}GROWABLE_HEAP_I32()[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}GROWABLE_HEAP_I32()[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>GROWABLE_HEAP_U16();shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>GROWABLE_HEAP_U32();shift=2}registerType(rawType,{name:name,"fromWireType":value=>{var length=GROWABLE_HEAP_U32()[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);GROWABLE_HEAP_U32()[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:ptr=>_free(ptr)})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":()=>undefined,"toWireType":(destructors,o)=>undefined})};var nowIsMonotonic=true;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var maybeExit=()=>{if(!keepRuntimeAlive()){try{if(ENVIRONMENT_IS_PTHREAD)__emscripten_thread_exit(EXITSTATUS);else _exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var __emscripten_thread_mailbox_await=pthread_ptr=>{if(typeof Atomics.waitAsync==="function"){var wait=Atomics.waitAsync(GROWABLE_HEAP_I32(),pthread_ptr>>2,pthread_ptr);wait.value.then(checkMailbox);var waitingAsync=pthread_ptr+128;Atomics.store(GROWABLE_HEAP_I32(),waitingAsync>>2,1)}};Module["__emscripten_thread_mailbox_await"]=__emscripten_thread_mailbox_await;var checkMailbox=()=>{var pthread_ptr=_pthread_self();if(pthread_ptr){__emscripten_thread_mailbox_await(pthread_ptr);callUserCallback(()=>__emscripten_check_mailbox())}};Module["checkMailbox"]=checkMailbox;var __emscripten_notify_mailbox_postmessage=(targetThreadId,currThreadId,mainThreadId)=>{if(targetThreadId==currThreadId){setTimeout(()=>checkMailbox())}else if(ENVIRONMENT_IS_PTHREAD){postMessage({"targetThread":targetThreadId,"cmd":"checkMailbox"})}else{var worker=PThread.pthreads[targetThreadId];if(!worker){return}worker.postMessage({"cmd":"checkMailbox"})}};var withStackSave=f=>{var stack=stackSave();var ret=f();stackRestore(stack);return ret};var proxyToMainThread=function(index,sync){var numCallArgs=arguments.length-2;var outerArgs=arguments;return withStackSave(()=>{var serializedNumCallArgs=numCallArgs;var args=stackAlloc(serializedNumCallArgs*8);var b=args>>3;for(var i=0;i{proxiedJSCallArgs.length=numCallArgs;var b=args>>3;for(var i=0;i{if(ENVIRONMENT_IS_NODE){PThread.pthreads[thread].ref()}};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl};var __emval_as=(handle,returnType,destructorsRef)=>{handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=Emval.toHandle(destructors);GROWABLE_HEAP_U32()[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var emval_methodCallers=[];var __emval_call_void_method=(caller,handle,methodName,args)=>{caller=emval_methodCallers[caller];handle=Emval.toValue(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)};var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>2],"parameter "+i)}return a};var emval_registeredMethods=[];var __emval_get_method_caller=(argCount,argTypes)=>{var types=emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var returnId=emval_registeredMethods[signatureName];if(returnId!==undefined){return returnId}var params=["retType"];var args=[retType];var argsList="";for(var i=0;i{name=getStringOrSymbol(name);return Emval.toHandle(Module[name])};var __emval_get_property=(handle,key)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])};var __emval_incref=handle=>{if(handle>4){emval_handles.get(handle).refcount+=1}};var craftEmvalAllocator=argCount=>{var argsList="";for(var i=0;iGROWABLE_HEAP_U32();var functionBody="return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n"+" var HEAPU32 = getMemory();\n";for(var i=0;i>2)], 'parameter "+i+"');\n"+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"+"argTypes += 4;\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return valueToHandle(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","valueToHandle","getMemory",functionBody)(requireRegisteredType,Module,Emval.toHandle,getMemory)};var emval_newers={};var __emval_new=(handle,argCount,argTypes,args)=>{handle=Emval.toValue(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)};var __emval_new_cstring=v=>Emval.toHandle(getStringOrSymbol(v));var __emval_run_destructors=handle=>{var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)};var _abort=()=>{abort("")};var warnOnce=text=>{if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var _emscripten_check_blocking_allowed=()=>{};var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};var _emscripten_exit_with_live_runtime=()=>{runtimeKeepalivePush();throw"unwind"};var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var _emscripten_get_now;_emscripten_get_now=()=>performance.timeOrigin+performance.now();var _emscripten_num_logical_cores=()=>{if(ENVIRONMENT_IS_NODE)return require("os").cpus().length;return navigator["hardwareConcurrency"]};var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=GROWABLE_HEAP_U8().length;requestedSize>>>=0;if(requestedSize<=oldSize){return false}var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>0]=str.charCodeAt(i)}GROWABLE_HEAP_I8()[buffer>>0]=0};var _environ_get=function(__environ,environ_buf){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(6,1,__environ,environ_buf);var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;GROWABLE_HEAP_U32()[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(7,1,penviron_count,penviron_buf_size);var strings=getEnvStrings();GROWABLE_HEAP_U32()[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);GROWABLE_HEAP_U32()[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(8,1,fd);try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=GROWABLE_HEAP_U32()[iov+4>>2];iov+=8;var curr=FS.read(stream,GROWABLE_HEAP_I8(),ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(10,1,fd,offset_low,offset_high,whence,newOffset);var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[newOffset>>2]=tempI64[0],GROWABLE_HEAP_I32()[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=GROWABLE_HEAP_U32()[iov+4>>2];iov+=8;var curr=FS.write(stream,GROWABLE_HEAP_I8(),ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret};function _fd_write(fd,iov,iovcnt,pnum){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(11,1,fd,iov,iovcnt,pnum);try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);GROWABLE_HEAP_U32()[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};var writeArrayToMemory=(array,buffer)=>{GROWABLE_HEAP_I8().set(array,buffer)};var _strftime=(s,maxsize,format,tm)=>{var tm_zone=GROWABLE_HEAP_U32()[tm+40>>2];var date={tm_sec:GROWABLE_HEAP_I32()[tm>>2],tm_min:GROWABLE_HEAP_I32()[tm+4>>2],tm_hour:GROWABLE_HEAP_I32()[tm+8>>2],tm_mday:GROWABLE_HEAP_I32()[tm+12>>2],tm_mon:GROWABLE_HEAP_I32()[tm+16>>2],tm_year:GROWABLE_HEAP_I32()[tm+20>>2],tm_wday:GROWABLE_HEAP_I32()[tm+24>>2],tm_yday:GROWABLE_HEAP_I32()[tm+28>>2],tm_isdst:GROWABLE_HEAP_I32()[tm+32>>2],tm_gmtoff:GROWABLE_HEAP_I32()[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":date=>getWeekBasedYear(date),"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1};var _strftime_l=(s,maxsize,format,tm,loc)=>_strftime(s,maxsize,format,tm);PThread.init();var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};handleAllocatorInit();init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");var proxiedFunctionTable=[_proc_exit,exitOnMainThread,pthreadCreateProxied,___syscall_fcntl64,___syscall_ioctl,___syscall_openat,_environ_get,_environ_sizes_get,_fd_close,_fd_read,_fd_seek,_fd_write];var wasmImports={d:___cxa_throw,J:___emscripten_init_main_thread_js,m:___emscripten_thread_cleanup,G:___pthread_create_js,q:___syscall_fcntl64,L:___syscall_ioctl,M:___syscall_openat,y:__embind_register_bigint,R:__embind_register_bool,Q:__embind_register_emval,s:__embind_register_float,h:__embind_register_function,g:__embind_register_integer,c:__embind_register_memory_view,r:__embind_register_std_string,k:__embind_register_std_wstring,S:__embind_register_void,P:__emscripten_get_now_is_monotonic,F:__emscripten_notify_mailbox_postmessage,H:__emscripten_receive_on_main_thread_js,I:__emscripten_thread_mailbox_await,O:__emscripten_thread_set_strongref,w:__emval_as,U:__emval_call_void_method,f:__emval_decref,V:__emval_get_method_caller,u:__emval_get_module_property,i:__emval_get_property,l:__emval_incref,t:__emval_new,j:__emval_new_cstring,v:__emval_run_destructors,b:_abort,n:_emscripten_check_blocking_allowed,N:_emscripten_exit_with_live_runtime,z:_emscripten_get_heap_max,e:_emscripten_get_now,A:_emscripten_num_logical_cores,E:_emscripten_resize_heap,C:_environ_get,D:_environ_sizes_get,T:_exit,o:_fd_close,K:_fd_read,x:_fd_seek,p:_fd_write,a:wasmMemory||Module["wasmMemory"],B:_strftime_l};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["W"])();var _free=a0=>(_free=wasmExports["Y"])(a0);var _malloc=a0=>(_malloc=wasmExports["Z"])(a0);var __emscripten_tls_init=Module["__emscripten_tls_init"]=()=>(__emscripten_tls_init=Module["__emscripten_tls_init"]=wasmExports["_"])();var _pthread_self=Module["_pthread_self"]=()=>(_pthread_self=Module["_pthread_self"]=wasmExports["$"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["aa"])(a0);var __embind_initialize_bindings=Module["__embind_initialize_bindings"]=()=>(__embind_initialize_bindings=Module["__embind_initialize_bindings"]=wasmExports["ba"])();var ___errno_location=()=>(___errno_location=wasmExports["ca"])();var __emscripten_thread_init=Module["__emscripten_thread_init"]=(a0,a1,a2,a3,a4,a5)=>(__emscripten_thread_init=Module["__emscripten_thread_init"]=wasmExports["da"])(a0,a1,a2,a3,a4,a5);var __emscripten_thread_crashed=Module["__emscripten_thread_crashed"]=()=>(__emscripten_thread_crashed=Module["__emscripten_thread_crashed"]=wasmExports["ea"])();var _emscripten_main_thread_process_queued_calls=()=>(_emscripten_main_thread_process_queued_calls=wasmExports["emscripten_main_thread_process_queued_calls"])();var _emscripten_main_runtime_thread_id=()=>(_emscripten_main_runtime_thread_id=wasmExports["emscripten_main_runtime_thread_id"])();var __emscripten_run_on_main_thread_js=(a0,a1,a2,a3)=>(__emscripten_run_on_main_thread_js=wasmExports["fa"])(a0,a1,a2,a3);var __emscripten_thread_free_data=a0=>(__emscripten_thread_free_data=wasmExports["ga"])(a0);var __emscripten_thread_exit=Module["__emscripten_thread_exit"]=a0=>(__emscripten_thread_exit=Module["__emscripten_thread_exit"]=wasmExports["ha"])(a0);var __emscripten_check_mailbox=Module["__emscripten_check_mailbox"]=()=>(__emscripten_check_mailbox=Module["__emscripten_check_mailbox"]=wasmExports["ia"])();var _emscripten_stack_set_limits=(a0,a1)=>(_emscripten_stack_set_limits=wasmExports["ja"])(a0,a1);var stackSave=()=>(stackSave=wasmExports["ka"])();var stackRestore=a0=>(stackRestore=wasmExports["la"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["ma"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["na"])(a0);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["oa"])(a0,a1,a2,a3,a4);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["pa"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["qa"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["ra"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["sa"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function intArrayFromBase64(s){if(typeof ENVIRONMENT_IS_NODE!="undefined"&&ENVIRONMENT_IS_NODE){var buf=Buffer.from(s,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}try{var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;i0){return}if(ENVIRONMENT_IS_PTHREAD){readyPromiseResolve(Module);initRuntime();startWorker(Module);return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + + + return moduleArg.ready +} + +); +})(); +if (typeof exports === 'object' && typeof module === 'object') + module.exports = whisper_factory; +else if (typeof define === 'function' && define['amd']) + define([], () => whisper_factory); diff --git a/bindings/ruby/Rakefile b/bindings/ruby/Rakefile new file mode 100644 index 0000000000000000000000000000000000000000..354d8ef2547b7ba1a3acfe5d50ff1222fa994c14 --- /dev/null +++ b/bindings/ruby/Rakefile @@ -0,0 +1,12 @@ +require 'rake/clean' + require 'rubygems/package' + +desc 'Build gem' +task :package do + spec_source = File.read File.join(File.dirname(__FILE__),'whispercpp.gemspec') + spec = nil + # see: http://gist.github.com/16215 + Thread.new { spec = eval("#{spec_source}") }.join + spec.validate + Gem::Package.build(spec) +end diff --git a/bindings/ruby/ext/.gitignore b/bindings/ruby/ext/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9f9b7abd60f9abaae4145594f5033cbc53472aab --- /dev/null +++ b/bindings/ruby/ext/.gitignore @@ -0,0 +1,9 @@ +Makefile +ggml.c +ggml.h +ggml-alloc.c +ggml-alloc.h +whisper.bundle +whisper.cpp +whisper.h +dr_wav.h diff --git a/bindings/ruby/ext/extconf.rb b/bindings/ruby/ext/extconf.rb new file mode 100644 index 0000000000000000000000000000000000000000..d791c413ff41d1f6941e23a829418104da5fb5c3 --- /dev/null +++ b/bindings/ruby/ext/extconf.rb @@ -0,0 +1,33 @@ +require 'mkmf' +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','whisper.cpp')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','whisper.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','whisper-mel.hpp')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-impl.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-aarch64.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-aarch64.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-alloc.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-alloc.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend-impl.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-common.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-quants.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-quants.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','examples','dr_wav.h')} .") + + +# need to use c++ compiler flags +$CXXFLAGS << ' -std=c++11' +# Set to true when building binary gems +if enable_config('static-stdlib', false) + $LDFLAGS << ' -static-libgcc -static-libstdc++' +end + +if enable_config('march-tune-native', false) + $CFLAGS << ' -march=native -mtune=native' + $CXXFLAGS << ' -march=native -mtune=native' +end + +create_makefile('whisper') diff --git a/bindings/ruby/ext/ggml-backend-impl.h b/bindings/ruby/ext/ggml-backend-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..f121e1de420facd4b5a9a8487480f60b4cc14e4a --- /dev/null +++ b/bindings/ruby/ext/ggml-backend-impl.h @@ -0,0 +1,141 @@ +#pragma once + +// ggml-backend internal header + +#include "ggml-backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + // + // Backend buffer + // + + // buffer type + typedef void * ggml_backend_buffer_type_context_t; + + struct ggml_backend_buffer_type_i { + const char * (*GGML_CALL get_name) (ggml_backend_buffer_type_t buft); + ggml_backend_buffer_t (*GGML_CALL alloc_buffer) (ggml_backend_buffer_type_t buft, size_t size); + size_t (*GGML_CALL get_alignment) (ggml_backend_buffer_type_t buft); // tensor alignment + size_t (*GGML_CALL get_max_size) (ggml_backend_buffer_type_t buft); // allocation max size + size_t (*GGML_CALL get_alloc_size) (ggml_backend_buffer_type_t buft, const struct ggml_tensor * tensor); // data size needed to allocate the tensor, including padding + bool (*GGML_CALL supports_backend)(ggml_backend_buffer_type_t buft, ggml_backend_t backend); // check if the buffer type is usable by the backend + // check if tensor data is in host memory + // should be equivalent to supports_backend(buft, ggml_backend_cpu_init()) + bool (*GGML_CALL is_host) (ggml_backend_buffer_type_t buft); + }; + + struct ggml_backend_buffer_type { + struct ggml_backend_buffer_type_i iface; + ggml_backend_buffer_type_context_t context; + }; + + // buffer + typedef void * ggml_backend_buffer_context_t; + + struct ggml_backend_buffer_i { + const char * (*GGML_CALL get_name) (ggml_backend_buffer_t buffer); + void (*GGML_CALL free_buffer)(ggml_backend_buffer_t buffer); + void * (*GGML_CALL get_base) (ggml_backend_buffer_t buffer); + void (*GGML_CALL init_tensor)(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + void (*GGML_CALL set_tensor) (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + void (*GGML_CALL get_tensor) (ggml_backend_buffer_t buffer, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + bool (*GGML_CALL cpy_tensor) (ggml_backend_buffer_t buffer, const struct ggml_tensor * src, struct ggml_tensor * dst); // dst is in the buffer, src may be in any buffer + void (*GGML_CALL clear) (ggml_backend_buffer_t buffer, uint8_t value); + void (*GGML_CALL reset) (ggml_backend_buffer_t buffer); // reset any internal state due to tensor initialization, such as tensor extras + }; + + struct ggml_backend_buffer { + struct ggml_backend_buffer_i iface; + ggml_backend_buffer_type_t buft; + ggml_backend_buffer_context_t context; + size_t size; + enum ggml_backend_buffer_usage usage; + }; + + GGML_CALL ggml_backend_buffer_t ggml_backend_buffer_init( + ggml_backend_buffer_type_t buft, + struct ggml_backend_buffer_i iface, + ggml_backend_buffer_context_t context, + size_t size); + + // do not use directly, use ggml_backend_tensor_copy instead + bool ggml_backend_buffer_copy_tensor(const struct ggml_tensor * src, struct ggml_tensor * dst); + + // buffer that contains a collection of buffers + GGML_CALL ggml_backend_buffer_t ggml_backend_multi_buffer_alloc_buffer(ggml_backend_buffer_t * buffers, size_t n_buffers); + GGML_CALL bool ggml_backend_buffer_is_multi_buffer(ggml_backend_buffer_t buffer); + GGML_CALL void ggml_backend_multi_buffer_set_usage(ggml_backend_buffer_t buffer, enum ggml_backend_buffer_usage usage); + + // + // Backend + // + + typedef void * ggml_backend_context_t; + + struct ggml_backend_i { + const char * (*GGML_CALL get_name)(ggml_backend_t backend); + + void (*GGML_CALL free)(ggml_backend_t backend); + + // buffer allocation + ggml_backend_buffer_type_t (*GGML_CALL get_default_buffer_type)(ggml_backend_t backend); + + // (optional) asynchronous tensor data access + void (*GGML_CALL set_tensor_async)(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + void (*GGML_CALL get_tensor_async)(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + bool (*GGML_CALL cpy_tensor_async)(ggml_backend_t backend_src, ggml_backend_t backend_dst, const struct ggml_tensor * src, struct ggml_tensor * dst); + + // (optional) complete all pending operations + void (*GGML_CALL synchronize)(ggml_backend_t backend); + + // compute graph with a plan (not used currently) + ggml_backend_graph_plan_t (*GGML_CALL graph_plan_create) (ggml_backend_t backend, const struct ggml_cgraph * cgraph); + void (*GGML_CALL graph_plan_free) (ggml_backend_t backend, ggml_backend_graph_plan_t plan); + + // compute graph with a plan + enum ggml_status (*GGML_CALL graph_plan_compute)(ggml_backend_t backend, ggml_backend_graph_plan_t plan); + // compute graph without a plan (async) + enum ggml_status (*GGML_CALL graph_compute) (ggml_backend_t backend, struct ggml_cgraph * cgraph); + + // check if the backend supports an operation + bool (*GGML_CALL supports_op)(ggml_backend_t backend, const struct ggml_tensor * op); + + // check if the backend wants to run an operation, even if the weights are allocated in a CPU buffer + // these should be expensive operations with large batch sizes that may benefit from running on this backend + // even if the weight has to be copied from the CPU temporarily + bool (*GGML_CALL offload_op)(ggml_backend_t backend, const struct ggml_tensor * op); + + // (optional) event synchronization + ggml_backend_event_t (*GGML_CALL event_new) (ggml_backend_t backend); + void (*GGML_CALL event_free) (ggml_backend_event_t event); + void (*GGML_CALL event_record) (ggml_backend_event_t event); + void (*GGML_CALL event_wait) (ggml_backend_t backend, ggml_backend_event_t event); + void (*GGML_CALL event_synchronize) (ggml_backend_event_t event); + }; + + struct ggml_backend { + ggml_guid_t guid; + + struct ggml_backend_i iface; + ggml_backend_context_t context; + }; + + struct ggml_backend_event { + ggml_backend_t backend; + void * context; + }; + + // + // Backend registry + // + + typedef ggml_backend_t (*GGML_CALL ggml_backend_init_fn)(const char * params, void * user_data); + + GGML_CALL void ggml_backend_register(const char * name, ggml_backend_init_fn init_fn, ggml_backend_buffer_type_t default_buffer_type, void * user_data); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-backend.c b/bindings/ruby/ext/ggml-backend.c new file mode 100644 index 0000000000000000000000000000000000000000..402d86ef3ac8b206d3acf602ec6dfb854d1f1bc4 --- /dev/null +++ b/bindings/ruby/ext/ggml-backend.c @@ -0,0 +1,2095 @@ +#include "ggml-backend-impl.h" +#include "ggml-alloc.h" +#include "ggml-impl.h" + +#include +#include +#include +#include +#include +#include + + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +// backend buffer type + +const char * ggml_backend_buft_name(ggml_backend_buffer_type_t buft) { + return buft->iface.get_name(buft); +} + +GGML_CALL ggml_backend_buffer_t ggml_backend_buft_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) { + return buft->iface.alloc_buffer(buft, size); +} + +size_t ggml_backend_buft_get_alignment(ggml_backend_buffer_type_t buft) { + return buft->iface.get_alignment(buft); +} + +size_t ggml_backend_buft_get_max_size(ggml_backend_buffer_type_t buft) { + // get_max_size is optional, defaults to SIZE_MAX + if (buft->iface.get_max_size) { + return buft->iface.get_max_size(buft); + } + return SIZE_MAX; +} + +GGML_CALL size_t ggml_backend_buft_get_alloc_size(ggml_backend_buffer_type_t buft, struct ggml_tensor * tensor) { + // get_alloc_size is optional, defaults to ggml_nbytes + if (buft->iface.get_alloc_size) { + size_t size = buft->iface.get_alloc_size(buft, tensor); + assert(size >= ggml_nbytes(tensor)); + return size; + } + return ggml_nbytes(tensor); +} + +bool ggml_backend_buft_supports_backend(ggml_backend_buffer_type_t buft, ggml_backend_t backend) { + return buft->iface.supports_backend(buft, backend); +} + +bool ggml_backend_buft_is_host(ggml_backend_buffer_type_t buft) { + if (buft->iface.is_host) { + return buft->iface.is_host(buft); + } + return false; +} + +// backend buffer + +GGML_CALL ggml_backend_buffer_t ggml_backend_buffer_init( + ggml_backend_buffer_type_t buft, + struct ggml_backend_buffer_i iface, + ggml_backend_buffer_context_t context, + size_t size) { + ggml_backend_buffer_t buffer = malloc(sizeof(struct ggml_backend_buffer)); + + (*buffer) = (struct ggml_backend_buffer) { + /* .interface = */ iface, + /* .buft = */ buft, + /* .context = */ context, + /* .size = */ size, + /* .usage = */ GGML_BACKEND_BUFFER_USAGE_ANY + }; + + return buffer; +} + +const char * ggml_backend_buffer_name(ggml_backend_buffer_t buffer) { + return buffer->iface.get_name(buffer); +} + +void ggml_backend_buffer_free(ggml_backend_buffer_t buffer) { + if (buffer == NULL) { + return; + } + + if (buffer->iface.free_buffer != NULL) { + buffer->iface.free_buffer(buffer); + } + free(buffer); +} + +size_t ggml_backend_buffer_get_size(ggml_backend_buffer_t buffer) { + return buffer->size; +} + +void * ggml_backend_buffer_get_base(ggml_backend_buffer_t buffer) { + void * base = buffer->iface.get_base(buffer); + + GGML_ASSERT(base != NULL && "backend buffer base cannot be NULL"); + + return base; +} + +GGML_CALL void ggml_backend_buffer_init_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + // init_tensor is optional + if (buffer->iface.init_tensor) { + buffer->iface.init_tensor(buffer, tensor); + } +} + +size_t ggml_backend_buffer_get_alignment (ggml_backend_buffer_t buffer) { + return ggml_backend_buft_get_alignment(ggml_backend_buffer_get_type(buffer)); +} + +size_t ggml_backend_buffer_get_max_size(ggml_backend_buffer_t buffer) { + return ggml_backend_buft_get_max_size(ggml_backend_buffer_get_type(buffer)); +} + +size_t ggml_backend_buffer_get_alloc_size(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + return ggml_backend_buft_get_alloc_size(ggml_backend_buffer_get_type(buffer), tensor); +} + +void ggml_backend_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) { + buffer->iface.clear(buffer, value); +} + +bool ggml_backend_buffer_is_host(ggml_backend_buffer_t buffer) { + return ggml_backend_buft_is_host(ggml_backend_buffer_get_type(buffer)); +} + +void ggml_backend_buffer_set_usage(ggml_backend_buffer_t buffer, enum ggml_backend_buffer_usage usage) { + buffer->usage = usage; + + // FIXME: add a generic callback to the buffer interface + if (ggml_backend_buffer_is_multi_buffer(buffer)) { + ggml_backend_multi_buffer_set_usage(buffer, usage); + } +} + +ggml_backend_buffer_type_t ggml_backend_buffer_get_type(ggml_backend_buffer_t buffer) { + return buffer->buft; +} + +void ggml_backend_buffer_reset(ggml_backend_buffer_t buffer) { + if (buffer->iface.reset) { + buffer->iface.reset(buffer); + } +} + +bool ggml_backend_buffer_copy_tensor(const struct ggml_tensor * src, struct ggml_tensor * dst) { + ggml_backend_buffer_t dst_buf = dst->view_src ? dst->view_src->buffer : dst->buffer; + if (dst_buf->iface.cpy_tensor) { + return src->buffer->iface.cpy_tensor(dst_buf, src, dst); + } + return false; +} + +// backend + +ggml_guid_t ggml_backend_guid(ggml_backend_t backend) { + if (backend == NULL) { + return NULL; + } + return backend->guid; +} + +const char * ggml_backend_name(ggml_backend_t backend) { + if (backend == NULL) { + return "NULL"; + } + return backend->iface.get_name(backend); +} + +void ggml_backend_free(ggml_backend_t backend) { + if (backend == NULL) { + return; + } + + backend->iface.free(backend); +} + +ggml_backend_buffer_type_t ggml_backend_get_default_buffer_type(ggml_backend_t backend) { + return backend->iface.get_default_buffer_type(backend); +} + +ggml_backend_buffer_t ggml_backend_alloc_buffer(ggml_backend_t backend, size_t size) { + return ggml_backend_buft_alloc_buffer(ggml_backend_get_default_buffer_type(backend), size); +} + +size_t ggml_backend_get_alignment(ggml_backend_t backend) { + return ggml_backend_buft_get_alignment(ggml_backend_get_default_buffer_type(backend)); +} + +size_t ggml_backend_get_max_size(ggml_backend_t backend) { + return ggml_backend_buft_get_max_size(ggml_backend_get_default_buffer_type(backend)); +} + +void ggml_backend_tensor_set_async(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor write out of bounds"); + + if (backend->iface.set_tensor_async == NULL) { + ggml_backend_tensor_set(tensor, data, offset, size); + } else { + backend->iface.set_tensor_async(backend, tensor, data, offset, size); + } +} + +void ggml_backend_tensor_get_async(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor read out of bounds"); + + if (backend->iface.get_tensor_async == NULL) { + ggml_backend_tensor_get(tensor, data, offset, size); + } else { + backend->iface.get_tensor_async(backend, tensor, data, offset, size); + } +} + +GGML_CALL void ggml_backend_tensor_set(struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; + + GGML_ASSERT(buf != NULL && "tensor buffer not set"); + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor write out of bounds"); + + if (!size) { + return; + } + + buf->iface.set_tensor(buf, tensor, data, offset, size); +} + +GGML_CALL void ggml_backend_tensor_get(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; + + GGML_ASSERT(buf != NULL && "tensor buffer not set"); + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor read out of bounds"); + + if (!size) { + return; + } + + buf->iface.get_tensor(buf, tensor, data, offset, size); +} + +void ggml_backend_synchronize(ggml_backend_t backend) { + if (backend->iface.synchronize == NULL) { + return; + } + + backend->iface.synchronize(backend); +} + +ggml_backend_graph_plan_t ggml_backend_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + GGML_ASSERT(backend->iface.graph_plan_create != NULL); + + return backend->iface.graph_plan_create(backend, cgraph); +} + +void ggml_backend_graph_plan_free(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + GGML_ASSERT(backend->iface.graph_plan_free != NULL); + + backend->iface.graph_plan_free(backend, plan); +} + +enum ggml_status ggml_backend_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + GGML_ASSERT(backend->iface.graph_plan_compute != NULL); + + return backend->iface.graph_plan_compute(backend, plan); +} + +enum ggml_status ggml_backend_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + enum ggml_status err = ggml_backend_graph_compute_async(backend, cgraph); + ggml_backend_synchronize(backend); + return err; +} + +enum ggml_status ggml_backend_graph_compute_async(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + return backend->iface.graph_compute(backend, cgraph); +} + +bool ggml_backend_supports_op(ggml_backend_t backend, const struct ggml_tensor * op) { + return backend->iface.supports_op(backend, op); +} + +bool ggml_backend_offload_op(ggml_backend_t backend, const struct ggml_tensor * op) { + if (backend->iface.offload_op != NULL) { + return backend->iface.offload_op(backend, op); + } + return false; +} + +// backend copy + +static bool ggml_are_same_layout(const struct ggml_tensor * a, const struct ggml_tensor * b) { + if (a->type != b->type) { + return false; + } + for (int i = 0; i < GGML_MAX_DIMS; i++) { + if (a->ne[i] != b->ne[i]) { + return false; + } + if (a->nb[i] != b->nb[i]) { + return false; + } + } + return true; +} + +void ggml_backend_tensor_copy(struct ggml_tensor * src, struct ggml_tensor * dst) { + GGML_ASSERT(ggml_are_same_layout(src, dst) && "cannot copy tensors with different layouts"); + + if (src == dst) { + return; + } + + if (ggml_backend_buffer_is_host(src->buffer)) { + ggml_backend_tensor_set(dst, src->data, 0, ggml_nbytes(src)); + } else if (ggml_backend_buffer_is_host(dst->buffer)) { + ggml_backend_tensor_get(src, dst->data, 0, ggml_nbytes(src)); + } else if (!ggml_backend_buffer_copy_tensor(src, dst)) { +#ifndef NDEBUG + fprintf(stderr, "%s: warning: slow copy from %s to %s\n", __func__, ggml_backend_buffer_name(src->buffer), ggml_backend_buffer_name(dst->buffer)); +#endif + size_t nbytes = ggml_nbytes(src); + void * data = malloc(nbytes); + ggml_backend_tensor_get(src, data, 0, nbytes); + ggml_backend_tensor_set(dst, data, 0, nbytes); + free(data); + } +} + +void ggml_backend_tensor_copy_async(ggml_backend_t backend_src, ggml_backend_t backend_dst, struct ggml_tensor * src, struct ggml_tensor * dst) { + GGML_ASSERT(ggml_are_same_layout(src, dst) && "cannot copy tensors with different layouts"); + + if (src == dst) { + return; + } + + if (backend_dst->iface.cpy_tensor_async != NULL) { + if (backend_dst->iface.cpy_tensor_async(backend_src, backend_dst, src, dst)) { + return; + } + } + + // an async copy would normally happen after all the queued operations on both backends are completed + // sync src, set_async dst + if (ggml_backend_buffer_is_host(src->buffer)) { + ggml_backend_synchronize(backend_src); + ggml_backend_tensor_set_async(backend_dst, dst, src->data, 0, ggml_nbytes(src)); + } else { + ggml_backend_synchronize(backend_src); + ggml_backend_tensor_copy(src, dst); + ggml_backend_synchronize(backend_dst); + } +} + +// events + +ggml_backend_event_t ggml_backend_event_new(ggml_backend_t backend) { + if (backend->iface.event_new == NULL) { + return NULL; + } + return backend->iface.event_new(backend); +} + +void ggml_backend_event_free(ggml_backend_event_t event) { + if (event == NULL) { + return; + } + event->backend->iface.event_free(event); +} + +void ggml_backend_event_record(ggml_backend_event_t event) { + GGML_ASSERT(event->backend->iface.event_record != NULL); + + event->backend->iface.event_record(event); +} + +void ggml_backend_event_synchronize(ggml_backend_event_t event) { + GGML_ASSERT(event->backend->iface.event_synchronize != NULL); + + event->backend->iface.event_synchronize(event); +} + +void ggml_backend_event_wait(ggml_backend_t backend, ggml_backend_event_t event) { + GGML_ASSERT(backend->iface.event_wait != NULL); + + backend->iface.event_wait(backend, event); +} + +// backend registry + +#define GGML_REG_MAX_BACKENDS 16 + +struct ggml_backend_reg { + char name[128]; + ggml_backend_init_fn init_fn; + ggml_backend_buffer_type_t default_buffer_type; + void * user_data; +}; + +static struct ggml_backend_reg ggml_backend_registry[GGML_REG_MAX_BACKENDS]; +static size_t ggml_backend_registry_count = 0; + +GGML_CALL static ggml_backend_t ggml_backend_reg_cpu_init(const char * params, void * user_data); + +GGML_CALL static void ggml_backend_registry_init(void) { + static bool initialized = false; + + if (initialized) { + return; + } + + initialized = true; + + ggml_backend_register("CPU", ggml_backend_reg_cpu_init, ggml_backend_cpu_buffer_type(), NULL); + + // add forward decls here to avoid including the backend headers +#ifdef GGML_USE_CUDA + extern GGML_CALL void ggml_backend_cuda_reg_devices(void); + ggml_backend_cuda_reg_devices(); +#endif + +#ifdef GGML_USE_SYCL + extern void ggml_backend_sycl_reg_devices(void); + ggml_backend_sycl_reg_devices(); +#endif + +#ifdef GGML_USE_METAL + extern GGML_CALL ggml_backend_t ggml_backend_reg_metal_init(const char * params, void * user_data); + extern GGML_CALL ggml_backend_buffer_type_t ggml_backend_metal_buffer_type(void); + ggml_backend_register("Metal", ggml_backend_reg_metal_init, ggml_backend_metal_buffer_type(), NULL); +#endif + +#ifdef GGML_USE_VULKAN + extern GGML_CALL int ggml_backend_vk_reg_devices(void); + ggml_backend_vk_reg_devices(); +#endif + +#ifdef GGML_USE_KOMPUTE + extern GGML_CALL void ggml_backend_kompute_reg_devices(void); + ggml_backend_kompute_reg_devices(); +#endif +} + +GGML_CALL void ggml_backend_register(const char * name, ggml_backend_init_fn init_fn, ggml_backend_buffer_type_t default_buffer_type, void * user_data) { + GGML_ASSERT(ggml_backend_registry_count < GGML_REG_MAX_BACKENDS); + + size_t id = ggml_backend_registry_count; + + ggml_backend_registry[id] = (struct ggml_backend_reg) { + /* .name = */ {0}, + /* .fn = */ init_fn, + /* .default_buffer_type = */ default_buffer_type, + /* .user_data = */ user_data, + }; + + snprintf(ggml_backend_registry[id].name, sizeof(ggml_backend_registry[id].name), "%s", name); + +#ifndef NDEBUG + fprintf(stderr, "%s: registered backend %s\n", __func__, name); +#endif + + ggml_backend_registry_count++; +} + +size_t ggml_backend_reg_get_count(void) { + ggml_backend_registry_init(); + + return ggml_backend_registry_count; +} + +size_t ggml_backend_reg_find_by_name(const char * name) { + ggml_backend_registry_init(); + + for (size_t i = 0; i < ggml_backend_registry_count; i++) { + // TODO: case insensitive in a portable way + if (strcmp(ggml_backend_registry[i].name, name) == 0) { + return i; + } + } + + // not found + return SIZE_MAX; +} + +// init from backend:params string +ggml_backend_t ggml_backend_reg_init_backend_from_str(const char * backend_str) { + ggml_backend_registry_init(); + + const char * params = strchr(backend_str, ':'); + char backend_name[128]; + if (params == NULL) { + snprintf(backend_name, sizeof(backend_name), "%s", backend_str); + params = ""; + } else { + snprintf(backend_name, sizeof(backend_name), "%.*s", (int)(params - backend_str), backend_str); + params++; + } + + size_t backend_i = ggml_backend_reg_find_by_name(backend_name); + + if (backend_i == SIZE_MAX) { + fprintf(stderr, "%s: backend %s not found\n", __func__, backend_name); + return NULL; + } + + return ggml_backend_reg_init_backend(backend_i, params); +} + +const char * ggml_backend_reg_get_name(size_t i) { + ggml_backend_registry_init(); + + GGML_ASSERT(i < ggml_backend_registry_count); + return ggml_backend_registry[i].name; +} + +ggml_backend_t ggml_backend_reg_init_backend(size_t i, const char * params) { + ggml_backend_registry_init(); + + GGML_ASSERT(i < ggml_backend_registry_count); + return ggml_backend_registry[i].init_fn(params, ggml_backend_registry[i].user_data); +} + +ggml_backend_buffer_type_t ggml_backend_reg_get_default_buffer_type(size_t i) { + ggml_backend_registry_init(); + + GGML_ASSERT(i < ggml_backend_registry_count); + return ggml_backend_registry[i].default_buffer_type; +} + +ggml_backend_buffer_t ggml_backend_reg_alloc_buffer(size_t i, size_t size) { + ggml_backend_registry_init(); + + GGML_ASSERT(i < ggml_backend_registry_count); + return ggml_backend_buft_alloc_buffer(ggml_backend_registry[i].default_buffer_type, size); +} + +// backend CPU + +static const size_t TENSOR_ALIGNMENT = 32; // required for mmap as gguf only guarantees 32-byte alignment + +GGML_CALL static const char * ggml_backend_cpu_buffer_name(ggml_backend_buffer_t buffer) { + return "CPU"; + + GGML_UNUSED(buffer); +} + +GGML_CALL static void * ggml_backend_cpu_buffer_get_base(ggml_backend_buffer_t buffer) { + uintptr_t data = (uintptr_t)buffer->context; + + // align the buffer + if (data % TENSOR_ALIGNMENT != 0) { + data = GGML_PAD(data, TENSOR_ALIGNMENT); + } + + return (void *)data; +} + +GGML_CALL static void ggml_backend_cpu_buffer_free_buffer(ggml_backend_buffer_t buffer) { + free(buffer->context); +} + +GGML_CALL static void ggml_backend_cpu_buffer_set_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + memcpy((char *)tensor->data + offset, data, size); + + GGML_UNUSED(buffer); +} + +GGML_CALL static void ggml_backend_cpu_buffer_get_tensor(ggml_backend_buffer_t buffer, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + memcpy(data, (const char *)tensor->data + offset, size); + + GGML_UNUSED(buffer); +} + +GGML_CALL static bool ggml_backend_cpu_buffer_cpy_tensor(ggml_backend_buffer_t buffer, const struct ggml_tensor * src, struct ggml_tensor * dst) { + if (ggml_backend_buffer_is_host(src->buffer)) { + memcpy(dst->data, src->data, ggml_nbytes(src)); + return true; + } + return false; + + GGML_UNUSED(buffer); +} + +GGML_CALL static void ggml_backend_cpu_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) { + memset(buffer->context, value, buffer->size); +} + +static struct ggml_backend_buffer_i cpu_backend_buffer_i = { + /* .get_name = */ ggml_backend_cpu_buffer_name, + /* .free_buffer = */ ggml_backend_cpu_buffer_free_buffer, + /* .get_base = */ ggml_backend_cpu_buffer_get_base, + /* .init_tensor = */ NULL, // no initialization required + /* .set_tensor = */ ggml_backend_cpu_buffer_set_tensor, + /* .get_tensor = */ ggml_backend_cpu_buffer_get_tensor, + /* .cpy_tensor = */ ggml_backend_cpu_buffer_cpy_tensor, + /* .clear = */ ggml_backend_cpu_buffer_clear, + /* .reset = */ NULL, +}; + +// for buffers from ptr, free is not called +static struct ggml_backend_buffer_i cpu_backend_buffer_i_from_ptr = { + /* .get_name = */ ggml_backend_cpu_buffer_name, + /* .free_buffer = */ NULL, // ptr is not owned by the buffer, so it does not need to be freed + /* .get_base = */ ggml_backend_cpu_buffer_get_base, + /* .init_tensor = */ NULL, // no initialization required + /* .set_tensor = */ ggml_backend_cpu_buffer_set_tensor, + /* .get_tensor = */ ggml_backend_cpu_buffer_get_tensor, + /* .cpy_tensor = */ ggml_backend_cpu_buffer_cpy_tensor, + /* .clear = */ ggml_backend_cpu_buffer_clear, + /* .reset = */ NULL, +}; + +GGML_CALL static const char * ggml_backend_cpu_buffer_type_get_name(ggml_backend_buffer_type_t buft) { + return "CPU"; + + GGML_UNUSED(buft); +} + +GGML_CALL static ggml_backend_buffer_t ggml_backend_cpu_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) { + size += TENSOR_ALIGNMENT; // malloc may return an address that is not aligned + void * data = malloc(size); // TODO: use GGML_ALIGNED_MALLOC (move to ggml-impl.h) + if (data == NULL) { + fprintf(stderr, "%s: failed to allocate buffer of size %zu\n", __func__, size); + return NULL; + } + + return ggml_backend_buffer_init(buft, cpu_backend_buffer_i, data, size); +} + +GGML_CALL static size_t ggml_backend_cpu_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) { + return TENSOR_ALIGNMENT; + + GGML_UNUSED(buft); +} + +GGML_CALL static bool ggml_backend_cpu_buffer_type_supports_backend(ggml_backend_buffer_type_t buft, ggml_backend_t backend) { + return ggml_backend_is_cpu(backend); + + GGML_UNUSED(buft); +} + +GGML_CALL static bool ggml_backend_cpu_buffer_type_is_host(ggml_backend_buffer_type_t buft) { + return true; + + GGML_UNUSED(buft); +} + +GGML_CALL ggml_backend_buffer_type_t ggml_backend_cpu_buffer_type(void) { + static struct ggml_backend_buffer_type ggml_backend_cpu_buffer_type = { + /* .iface = */ { + /* .get_name = */ ggml_backend_cpu_buffer_type_get_name, + /* .alloc_buffer = */ ggml_backend_cpu_buffer_type_alloc_buffer, + /* .get_alignment = */ ggml_backend_cpu_buffer_type_get_alignment, + /* .get_max_size = */ NULL, // defaults to SIZE_MAX + /* .get_alloc_size = */ NULL, // defaults to ggml_nbytes + /* .supports_backend = */ ggml_backend_cpu_buffer_type_supports_backend, + /* .is_host = */ ggml_backend_cpu_buffer_type_is_host, + }, + /* .context = */ NULL, + }; + + return &ggml_backend_cpu_buffer_type; +} + +#ifdef GGML_USE_CPU_HBM + +// buffer type HBM + +#include + +GGML_CALL static const char * ggml_backend_cpu_hbm_buffer_type_get_name(ggml_backend_buffer_type_t buft) { + return "CPU_HBM"; + + GGML_UNUSED(buft); +} + +GGML_CALL static const char * ggml_backend_cpu_hbm_buffer_get_name(ggml_backend_buffer_t buf) { + return "CPU_HBM"; + + GGML_UNUSED(buf); +} + +GGML_CALL static void ggml_backend_cpu_hbm_buffer_free_buffer(ggml_backend_buffer_t buffer) { + hbw_free(buffer->context); +} + +GGML_CALL static ggml_backend_buffer_t ggml_backend_cpu_hbm_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) { + //void * ptr = hbw_malloc(size); + void * ptr; + int result = hbw_posix_memalign(&ptr, ggml_backend_cpu_buffer_type_get_alignment(buft), size); + if (result != 0) { + fprintf(stderr, "failed to allocate HBM buffer of size %zu\n", size); + return NULL; + } + + ggml_backend_buffer_t buffer = ggml_backend_cpu_buffer_from_ptr(ptr, size); + buffer->buft = buft; + buffer->iface.get_name = ggml_backend_cpu_hbm_buffer_get_name; + buffer->iface.free_buffer = ggml_backend_cpu_hbm_buffer_free_buffer; + + return buffer; +} + +ggml_backend_buffer_type_t ggml_backend_cpu_hbm_buffer_type(void) { + static struct ggml_backend_buffer_type ggml_backend_cpu_buffer_type_hbm = { + /* .iface = */ { + /* .get_name = */ ggml_backend_cpu_hbm_buffer_type_get_name, + /* .alloc_buffer = */ ggml_backend_cpu_hbm_buffer_type_alloc_buffer, + /* .get_alignment = */ ggml_backend_cpu_buffer_type_get_alignment, + /* .get_max_size = */ NULL, // defaults to SIZE_MAX + /* .get_alloc_size = */ NULL, // defaults to ggml_nbytes + /* .supports_backend = */ ggml_backend_cpu_buffer_type_supports_backend, + /* .is_host = */ ggml_backend_cpu_buffer_type_is_host, + }, + /* .context = */ NULL, + }; + + return &ggml_backend_cpu_buffer_type_hbm; +} +#endif + +struct ggml_backend_cpu_context { + int n_threads; + void * work_data; + size_t work_size; + + ggml_abort_callback abort_callback; + void * abort_callback_data; +}; + +GGML_CALL static const char * ggml_backend_cpu_name(ggml_backend_t backend) { + return "CPU"; + + GGML_UNUSED(backend); +} + +GGML_CALL static void ggml_backend_cpu_free(ggml_backend_t backend) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + free(cpu_ctx->work_data); + free(cpu_ctx); + free(backend); +} + +GGML_CALL static ggml_backend_buffer_type_t ggml_backend_cpu_get_default_buffer_type(ggml_backend_t backend) { + return ggml_backend_cpu_buffer_type(); + + GGML_UNUSED(backend); +} + +struct ggml_backend_plan_cpu { + struct ggml_cplan cplan; + struct ggml_cgraph cgraph; +}; + +GGML_CALL static ggml_backend_graph_plan_t ggml_backend_cpu_graph_plan_create(ggml_backend_t backend, const struct ggml_cgraph * cgraph) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + + struct ggml_backend_plan_cpu * cpu_plan = malloc(sizeof(struct ggml_backend_plan_cpu)); + + cpu_plan->cplan = ggml_graph_plan(cgraph, cpu_ctx->n_threads); + cpu_plan->cgraph = *cgraph; // FIXME: deep copy + + if (cpu_plan->cplan.work_size > 0) { + cpu_plan->cplan.work_data = malloc(cpu_plan->cplan.work_size); + if (cpu_plan->cplan.work_data == NULL) { + free(cpu_plan); + return NULL; + } + } + + cpu_plan->cplan.abort_callback = cpu_ctx->abort_callback; + cpu_plan->cplan.abort_callback_data = cpu_ctx->abort_callback_data; + + return cpu_plan; +} + +GGML_CALL static void ggml_backend_cpu_graph_plan_free(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + struct ggml_backend_plan_cpu * cpu_plan = (struct ggml_backend_plan_cpu *)plan; + + free(cpu_plan->cplan.work_data); + free(cpu_plan); + + GGML_UNUSED(backend); +} + +GGML_CALL static enum ggml_status ggml_backend_cpu_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + struct ggml_backend_plan_cpu * cpu_plan = (struct ggml_backend_plan_cpu *)plan; + + return ggml_graph_compute(&cpu_plan->cgraph, &cpu_plan->cplan); + + GGML_UNUSED(backend); +} + +GGML_CALL static enum ggml_status ggml_backend_cpu_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + + struct ggml_cplan cplan = ggml_graph_plan(cgraph, cpu_ctx->n_threads); + + if (cpu_ctx->work_size < cplan.work_size) { + free(cpu_ctx->work_data); + cpu_ctx->work_data = malloc(cplan.work_size); + if (cpu_ctx->work_data == NULL) { + cpu_ctx->work_size = 0; + return GGML_STATUS_ALLOC_FAILED; + } + cpu_ctx->work_size = cplan.work_size; + } + cplan.work_data = cpu_ctx->work_data; + + cplan.abort_callback = cpu_ctx->abort_callback; + cplan.abort_callback_data = cpu_ctx->abort_callback_data; + + return ggml_graph_compute(cgraph, &cplan); +} + +GGML_CALL static bool ggml_backend_cpu_supports_op(ggml_backend_t backend, const struct ggml_tensor * op) { + switch (op->op) { + case GGML_OP_CPY: + return op->type != GGML_TYPE_IQ2_XXS && op->type != GGML_TYPE_IQ2_XS && op->type != GGML_TYPE_IQ1_S; // missing type_traits.from_float + case GGML_OP_MUL_MAT: + return op->src[1]->type == GGML_TYPE_F32 || op->src[1]->type == ggml_internal_get_type_traits(op->src[0]->type).vec_dot_type; + default: + return true; + } + + GGML_UNUSED(backend); +} + +static struct ggml_backend_i cpu_backend_i = { + /* .get_name = */ ggml_backend_cpu_name, + /* .free = */ ggml_backend_cpu_free, + /* .get_default_buffer_type = */ ggml_backend_cpu_get_default_buffer_type, + /* .set_tensor_async = */ NULL, + /* .get_tensor_async = */ NULL, + /* .cpy_tensor_async = */ NULL, + /* .synchronize = */ NULL, + /* .graph_plan_create = */ ggml_backend_cpu_graph_plan_create, + /* .graph_plan_free = */ ggml_backend_cpu_graph_plan_free, + /* .graph_plan_compute = */ ggml_backend_cpu_graph_plan_compute, + /* .graph_compute = */ ggml_backend_cpu_graph_compute, + /* .supports_op = */ ggml_backend_cpu_supports_op, + /* .offload_op = */ NULL, + /* .event_new = */ NULL, + /* .event_free = */ NULL, + /* .event_record = */ NULL, + /* .event_wait = */ NULL, + /* .event_synchronize = */ NULL, +}; + +static ggml_guid_t ggml_backend_cpu_guid(void) { + static ggml_guid guid = { 0xaa, 0x67, 0xc7, 0x43, 0x96, 0xe6, 0xa3, 0x8a, 0xe3, 0xaf, 0xea, 0x92, 0x36, 0xbc, 0xfc, 0x89 }; + return &guid; +} + +ggml_backend_t ggml_backend_cpu_init(void) { + struct ggml_backend_cpu_context * ctx = malloc(sizeof(struct ggml_backend_cpu_context)); + if (ctx == NULL) { + return NULL; + } + + ctx->n_threads = GGML_DEFAULT_N_THREADS; + ctx->work_data = NULL; + ctx->work_size = 0; + ctx->abort_callback = NULL; + ctx->abort_callback_data = NULL; + + ggml_backend_t cpu_backend = malloc(sizeof(struct ggml_backend)); + if (cpu_backend == NULL) { + free(ctx); + return NULL; + } + + *cpu_backend = (struct ggml_backend) { + /* .guid = */ ggml_backend_cpu_guid(), + /* .interface = */ cpu_backend_i, + /* .context = */ ctx + }; + return cpu_backend; +} + +GGML_CALL bool ggml_backend_is_cpu(ggml_backend_t backend) { + return backend != NULL && ggml_guid_matches(backend->guid, ggml_backend_cpu_guid()); +} + +void ggml_backend_cpu_set_n_threads(ggml_backend_t backend_cpu, int n_threads) { + GGML_ASSERT(ggml_backend_is_cpu(backend_cpu)); + + struct ggml_backend_cpu_context * ctx = (struct ggml_backend_cpu_context *)backend_cpu->context; + ctx->n_threads = n_threads; +} + +void ggml_backend_cpu_set_abort_callback(ggml_backend_t backend_cpu, ggml_abort_callback abort_callback, void * abort_callback_data) { + GGML_ASSERT(ggml_backend_is_cpu(backend_cpu)); + + struct ggml_backend_cpu_context * ctx = (struct ggml_backend_cpu_context *)backend_cpu->context; + ctx->abort_callback = abort_callback; + ctx->abort_callback_data = abort_callback_data; +} + +GGML_CALL ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(void * ptr, size_t size) { + GGML_ASSERT((uintptr_t)ptr % TENSOR_ALIGNMENT == 0 && "buffer pointer must be aligned"); + return ggml_backend_buffer_init(ggml_backend_cpu_buffer_type(), cpu_backend_buffer_i_from_ptr, ptr, size); +} + +GGML_CALL static ggml_backend_t ggml_backend_reg_cpu_init(const char * params, void * user_data) { + return ggml_backend_cpu_init(); + + GGML_UNUSED(params); + GGML_UNUSED(user_data); +} + +// multi-buffer buffer + +struct ggml_backend_multi_buffer_context { + ggml_backend_buffer_t * buffers; + size_t n_buffers; +}; + +typedef struct ggml_backend_multi_buffer_context * ggml_backend_multi_buffer_context_t; + +GGML_CALL static const char * ggml_backend_multi_buffer_get_name(ggml_backend_buffer_t buffer) { + ggml_backend_multi_buffer_context_t ctx = (ggml_backend_multi_buffer_context_t) buffer->context; + + return ctx->buffers[0]->iface.get_name(ctx->buffers[0]); +} + +GGML_CALL static void ggml_backend_multi_buffer_free_buffer(ggml_backend_buffer_t buffer) { + ggml_backend_multi_buffer_context_t ctx = (ggml_backend_multi_buffer_context_t) buffer->context; + for (size_t i = 0; i < ctx->n_buffers; i++) { + ggml_backend_buffer_free(ctx->buffers[i]); + } + + free(ctx->buffers); + free(ctx); +} + +GGML_CALL static void ggml_backend_multi_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) { + ggml_backend_multi_buffer_context_t ctx = (ggml_backend_multi_buffer_context_t) buffer->context; + for (size_t i = 0; i < ctx->n_buffers; i++) { + ggml_backend_buffer_clear(ctx->buffers[i], value); + } +} + +static struct ggml_backend_buffer_i ggml_backend_multi_buffer_context_interface(void) { + static struct ggml_backend_buffer_i multi_backend_buffer_i = { + /* .get_name = */ ggml_backend_multi_buffer_get_name, + /* .free_buffer = */ ggml_backend_multi_buffer_free_buffer, + /* .get_base = */ NULL, + /* .init_tensor = */ NULL, + /* .set_tensor = */ NULL, + /* .get_tensor = */ NULL, + /* .cpy_tensor = */ NULL, + /* .clear = */ ggml_backend_multi_buffer_clear, + /* .reset = */ NULL, + }; + + return multi_backend_buffer_i; +} + +GGML_CALL ggml_backend_buffer_t ggml_backend_multi_buffer_alloc_buffer(ggml_backend_buffer_t * buffers, size_t n_buffers) { + ggml_backend_multi_buffer_context_t ctx = (ggml_backend_multi_buffer_context_t) malloc(sizeof(struct ggml_backend_multi_buffer_context)); + ctx->n_buffers = n_buffers; + ctx->buffers = (ggml_backend_buffer_t *) malloc(n_buffers * sizeof(ggml_backend_buffer_t)); + + GGML_ASSERT(ctx->buffers != NULL); + + size_t total_size = 0; + for (size_t i = 0; i < n_buffers; i++) { + ctx->buffers[i] = buffers[i]; + total_size += ggml_backend_buffer_get_size(buffers[i]); + } + + return ggml_backend_buffer_init(buffers[0]->buft, ggml_backend_multi_buffer_context_interface(), ctx, total_size); +} + +GGML_CALL bool ggml_backend_buffer_is_multi_buffer(ggml_backend_buffer_t buffer) { + return buffer->iface.get_name == ggml_backend_multi_buffer_get_name; +} + +GGML_CALL void ggml_backend_multi_buffer_set_usage(ggml_backend_buffer_t buffer, enum ggml_backend_buffer_usage usage) { + GGML_ASSERT(ggml_backend_buffer_is_multi_buffer(buffer)); + ggml_backend_multi_buffer_context_t ctx = (ggml_backend_multi_buffer_context_t) buffer->context; + for (size_t i = 0; i < ctx->n_buffers; i++) { + ggml_backend_buffer_set_usage(ctx->buffers[i], usage); + } +} + +// creates a copy of the tensor with the same memory layout +static struct ggml_tensor * ggml_dup_tensor_layout(struct ggml_context * ctx, const struct ggml_tensor * tensor) { + struct ggml_tensor * dup = ggml_dup_tensor(ctx, tensor); + for (int i = 0; i < GGML_MAX_DIMS; i++) { + dup->nb[i] = tensor->nb[i]; + } + return dup; +} + +static bool ggml_is_view_op(enum ggml_op op) { + return op == GGML_OP_VIEW || op == GGML_OP_RESHAPE || op == GGML_OP_PERMUTE || op == GGML_OP_TRANSPOSE; +} + +// scheduler + +#ifndef GGML_SCHED_MAX_BACKENDS +#define GGML_SCHED_MAX_BACKENDS 16 +#endif + +#ifndef GGML_SCHED_MAX_SPLITS +#define GGML_SCHED_MAX_SPLITS 2048 +#endif + +#ifndef GGML_SCHED_MAX_SPLIT_INPUTS +#define GGML_SCHED_MAX_SPLIT_INPUTS GGML_MAX_SRC +#endif + +#ifndef GGML_SCHED_MAX_COPIES +#define GGML_SCHED_MAX_COPIES 4 +#endif + +struct ggml_backend_sched_split { + int backend_id; + int i_start; + int i_end; + struct ggml_tensor * inputs[GGML_SCHED_MAX_SPLIT_INPUTS]; + int n_inputs; + // graph view of this split + struct ggml_cgraph graph; +}; + +struct ggml_backend_sched { + bool is_reset; // true if the scheduler has been reset since the last graph split + bool is_alloc; + + int n_backends; + + ggml_backend_t backends[GGML_SCHED_MAX_BACKENDS]; + ggml_backend_buffer_type_t bufts[GGML_SCHED_MAX_BACKENDS]; + ggml_gallocr_t galloc; + + // hash keys of the nodes in the graph + struct ggml_hash_set hash_set; + // hash values + int * tensor_backend_id; + struct ggml_tensor * (* tensor_copies)[GGML_SCHED_MAX_BACKENDS][GGML_SCHED_MAX_COPIES]; + + int * node_backend_ids; // [graph_size] + int * leaf_backend_ids; // [graph_size] + + // copy of the graph with modified inputs + struct ggml_cgraph * graph; + + // graph splits + struct ggml_backend_sched_split * splits; + int n_splits; + int splits_capacity; + + // pipeline parallelism support + int n_copies; + int cur_copy; + ggml_backend_event_t events[GGML_SCHED_MAX_BACKENDS][GGML_SCHED_MAX_COPIES]; + struct ggml_tensor * graph_inputs[GGML_SCHED_MAX_SPLIT_INPUTS]; + int n_graph_inputs; + + struct ggml_context * ctx; + + ggml_backend_sched_eval_callback callback_eval; + void * callback_eval_user_data; + + // align context_buffer to GGML_MEM_ALIGN +#ifdef _MSC_VER + __declspec(align(GGML_MEM_ALIGN)) +#else + __attribute__((aligned(GGML_MEM_ALIGN))) +#endif + char context_buffer[GGML_SCHED_MAX_SPLITS*GGML_SCHED_MAX_SPLIT_INPUTS*2*sizeof(struct ggml_tensor) + sizeof(struct ggml_cgraph)]; +}; + +#define hash_id(tensor) ggml_hash_find_or_insert(sched->hash_set, tensor) +#define tensor_backend_id(tensor) sched->tensor_backend_id[hash_id(tensor)] + +// returns the priority of the backend, lower id is higher priority +static int ggml_backend_sched_backend_id(ggml_backend_sched_t sched, ggml_backend_t backend) { + for (int i = 0; i < sched->n_backends; i++) { + if (sched->backends[i] == backend) { + return i; + } + } + return -1; +} + +static int ggml_backend_sched_backend_from_buffer(ggml_backend_sched_t sched, const struct ggml_tensor * tensor) { + ggml_backend_buffer_t buffer = tensor->buffer; + if (buffer == NULL) { + return -1; + } + + // find highest prio backend that supports the buffer type + for (int i = 0; i < sched->n_backends; i++) { + if (ggml_backend_buft_supports_backend(buffer->buft, sched->backends[i])) { + return i; + } + } + + fprintf(stderr, "%s: error: no backend supports buffer type %s used in tensor %s\n", + __func__, ggml_backend_buffer_name(buffer), tensor->name); + GGML_ASSERT(false); + + return -1; +} + +#if 0 +static char causes[GGML_DEFAULT_GRAPH_SIZE*16 + GGML_SCHED_MAX_SPLITS*GGML_SCHED_MAX_SPLIT_INPUTS][128]; // debug only +#define SET_CAUSE(node, ...) sprintf(causes[hash_id(node)], __VA_ARGS__) +#define GET_CAUSE(node) causes[hash_id(node)] +#else +#define SET_CAUSE(node, ...) +#define GET_CAUSE(node) "" +#endif + +// returns the backend that should be used for the node based on the current locations +static int ggml_backend_sched_backend_id_from_cur(ggml_backend_sched_t sched, struct ggml_tensor * tensor) { + // TODO: use supports_op to check if the backend supports the op + + // assign pre-allocated nodes to their backend + int cur_backend_id = ggml_backend_sched_backend_from_buffer(sched, tensor); + if (cur_backend_id != -1) { + SET_CAUSE(tensor, "1.dst"); + return cur_backend_id; + } + + // view_src + if (tensor->view_src != NULL) { + cur_backend_id = ggml_backend_sched_backend_from_buffer(sched, tensor->view_src); + if (cur_backend_id != -1) { + SET_CAUSE(tensor, "1.vsrc"); + return cur_backend_id; + } + } + + // graph input + if (tensor->flags & GGML_TENSOR_FLAG_INPUT) { + cur_backend_id = sched->n_backends - 1; // last backend (assumed CPU) + SET_CAUSE(tensor, "1.inp"); + return cur_backend_id; + } + + // assign nodes that use weights to the backend of the weights + // operations with weights are preferably run on the same backend as the weights + for (int i = 0; i < GGML_MAX_SRC; i++) { + const struct ggml_tensor * src = tensor->src[i]; + if (src == NULL) { + continue; + } + if (src->buffer != NULL && src->buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS) { + int src_backend_id = ggml_backend_sched_backend_from_buffer(sched, src); + // check if a backend with higher prio wants to offload the op + if (src_backend_id == sched->n_backends - 1) { + for (int b = 0; b < src_backend_id; b++) { + if (ggml_backend_offload_op(sched->backends[b], tensor)) { + SET_CAUSE(tensor, "1.off"); + return b; + } + } + } + SET_CAUSE(tensor, "1.wgt%d", i); + return src_backend_id; + } + } + + return -1; +} + +static char * fmt_size(size_t size) { + static char buffer[128]; + if (size >= 1024*1024) { + sprintf(buffer, "%zuM", size/1024/1024); + } else { + sprintf(buffer, "%zuK", size/1024); + } + return buffer; +} + +static void ggml_backend_sched_print_assignments(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + int cur_split = 0; + for (int i = 0; i < graph->n_nodes; i++) { + if (cur_split < sched->n_splits && i == sched->splits[cur_split].i_start) { + ggml_backend_t split_backend = sched->backends[sched->splits[cur_split].backend_id]; + fprintf(stderr, "\n## SPLIT #%d: %s # %d inputs: ", cur_split, ggml_backend_name(split_backend), + sched->splits[cur_split].n_inputs); + for (int j = 0; j < sched->splits[cur_split].n_inputs; j++) { + fprintf(stderr, "[%s (%5.5s)] ", sched->splits[cur_split].inputs[j]->name, + fmt_size(ggml_nbytes(sched->splits[cur_split].inputs[j]))); + } + fprintf(stderr, "\n"); + cur_split++; + } + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + ggml_backend_t tensor_backend = ggml_backend_sched_get_tensor_backend(sched, node); + fprintf(stderr, "node #%3d (%10.10s): %20.20s (%5.5s) [%5.5s %8.8s]:", i, ggml_op_name(node->op), node->name, + fmt_size(ggml_nbytes(node)), tensor_backend ? ggml_backend_name(tensor_backend) : "NULL", GET_CAUSE(node)); + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + continue; + } + ggml_backend_t src_backend = ggml_backend_sched_get_tensor_backend(sched, src); + fprintf(stderr, " %20.20s (%5.5s) [%5.5s %8.8s]", src->name, + fmt_size(ggml_nbytes(src)), src_backend ? ggml_backend_name(src_backend) : "NULL", GET_CAUSE(src)); + } + fprintf(stderr, "\n"); + } +} + +//#define DEBUG_PASS1 +//#define DEBUG_PASS2 +//#define DEBUG_PASS3 +//#define DEBUG_PASS4 + +// assigns backends to ops and splits the graph into subgraphs that can be computed on the same backend +static void ggml_backend_sched_split_graph(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + // reset splits + sched->n_splits = 0; + sched->n_graph_inputs = 0; + sched->is_reset = false; + + struct ggml_init_params params = { + /* .mem_size = */ sizeof(sched->context_buffer), + /* .mem_buffer = */ sched->context_buffer, + /* .no_alloc = */ true + }; + + ggml_free(sched->ctx); + + sched->ctx = ggml_init(params); + if (sched->ctx == NULL) { + fprintf(stderr, "%s: failed to initialize context\n", __func__); + GGML_ASSERT(false); + } + + // pass 1: assign backends to ops with pre-allocated inputs + for (int i = 0; i < graph->n_leafs; i++) { + struct ggml_tensor * leaf = graph->leafs[i]; + int * leaf_backend_id = &tensor_backend_id(leaf); + if (*leaf_backend_id != -1) { + // do not overwrite user assignments + continue; + } + *leaf_backend_id = ggml_backend_sched_backend_id_from_cur(sched, leaf); + } + + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + int * node_backend_id = &tensor_backend_id(node); + if (*node_backend_id != -1) { + // do not overwrite user assignments + continue; + } + *node_backend_id = ggml_backend_sched_backend_id_from_cur(sched, node); + // src + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + continue; + } + int * src_backend_id = &tensor_backend_id(src); + if (*src_backend_id == -1) { + *src_backend_id = ggml_backend_sched_backend_id_from_cur(sched, src); + } + } + } +#ifdef DEBUG_PASS1 + fprintf(stderr, "PASS 1 ASSIGNMENTS\n"); ggml_backend_sched_print_assignments(sched, graph); +#endif + + // pass 2: expand current backend assignments + // assign the same backend to adjacent nodes + // expand gpu backends (i.e. non last prio) up and down, ignoring cpu (the lowest priority backend) + // thus, cpu will never be used unless weights are on cpu, or there are no gpu ops between cpu ops + + + // pass 2.2 expand gpu down + { + int cur_backend_id = -1; + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + int * node_backend_id = &tensor_backend_id(node); + if (*node_backend_id != -1) { + if (*node_backend_id == sched->n_backends - 1) { + // skip cpu (lowest prio backend) + cur_backend_id = -1; + } else { + cur_backend_id = *node_backend_id; + } + } else { + *node_backend_id = cur_backend_id; + SET_CAUSE(node, "2.2"); + } + } + } + // pass 2.1 expand gpu up + { + int cur_backend_id = -1; + for (int i = graph->n_nodes - 1; i >= 0; i--) { + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + int * node_backend_id = &tensor_backend_id(node); + if (*node_backend_id != -1) { + if (*node_backend_id == sched->n_backends - 1) { + // skip cpu (lowest prio backend) + cur_backend_id = -1; + } else { + cur_backend_id = *node_backend_id; + } + } else { + *node_backend_id = cur_backend_id; + SET_CAUSE(node, "2.1"); + } + } + } + // pass 2.4 expand rest down + { + int cur_backend_id = -1; + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + int * node_backend_id = &tensor_backend_id(node); + if (*node_backend_id != -1) { + cur_backend_id = *node_backend_id; + } else { + *node_backend_id = cur_backend_id; + SET_CAUSE(node, "2.4"); + } + } + } + // pass 2.3 expand rest up + { + int cur_backend_id = -1; + for (int i = graph->n_nodes - 1; i >= 0; i--) { + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + int * node_backend_id = &tensor_backend_id(node); + if (*node_backend_id != -1) { + cur_backend_id = *node_backend_id; + } else { + *node_backend_id = cur_backend_id; + SET_CAUSE(node, "2.3"); + } + } + } + +#ifdef DEBUG_PASS2 + fprintf(stderr, "PASS 2 ASSIGNMENTS\n"); ggml_backend_sched_print_assignments(sched, graph); +#endif + + // pass 3: assign backends to remaining src from dst and view_src + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + int * cur_backend_id = &tensor_backend_id(node); + if (node->view_src != NULL && *cur_backend_id == -1) { + *cur_backend_id = tensor_backend_id(node->view_src); + SET_CAUSE(node, "3.vsrc"); + } + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + continue; + } + int * src_backend_id = &tensor_backend_id(src); + if (*src_backend_id == -1) { + if (src->view_src != NULL) { + // views are always on the same backend as the source + *src_backend_id = tensor_backend_id(src->view_src); + SET_CAUSE(src, "3.vsrc"); + } else { + *src_backend_id = *cur_backend_id; + SET_CAUSE(src, "3.cur"); + } + } + } + } +#ifdef DEBUG_PASS3 + fprintf(stderr, "PASS 3 ASSIGNMENTS\n"); ggml_backend_sched_print_assignments(sched, graph); +#endif + + // pass 4: split graph, find tensors that need to be copied + { + int i_split = 0; + struct ggml_backend_sched_split * split = &sched->splits[0]; + // find the backend of the first split, skipping view ops + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + if (!ggml_is_view_op(node->op)) { + split->backend_id = tensor_backend_id(node); + break; + } + } + split->i_start = 0; + split->n_inputs = 0; + memset(split->inputs, 0, sizeof(split->inputs)); //HACK + int cur_backend_id = split->backend_id; + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + + if (ggml_is_view_op(node->op)) { + continue; + } + + const int node_backend_id = tensor_backend_id(node); + + GGML_ASSERT(node_backend_id != -1); // all nodes should be assigned by now + + // check if we should start a new split based on the sources of the current node + bool need_new_split = false; + if (node_backend_id == cur_backend_id && split->n_inputs > 0) { + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + continue; + } + // check if a weight is on a different backend + // by starting a new split, the memory of the previously offloaded weights can be reused + if (src->buffer != NULL && src->buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS) { + int src_backend_id = tensor_backend_id(src); + if (src_backend_id != -1 && src_backend_id != cur_backend_id) { + need_new_split = true; + break; + } + } + // check if the split has too many inputs + if (split->n_inputs == GGML_SCHED_MAX_SPLIT_INPUTS) { + const size_t id = hash_id(src); + int src_backend_id = sched->tensor_backend_id[id]; + if (src_backend_id != cur_backend_id && sched->tensor_copies[hash_id(src)][cur_backend_id][0] == NULL) { + //printf("starting new split because of too many inputs: node %s, input %s\n", node->name, src->name); + need_new_split = true; + break; + } + } + } + } + + if (node_backend_id != cur_backend_id || need_new_split) { + split->i_end = i; + i_split++; + if (i_split >= sched->splits_capacity) { + sched->splits_capacity *= 2; + sched->splits = realloc(sched->splits, sched->splits_capacity * sizeof(struct ggml_backend_sched_split)); + GGML_ASSERT(sched->splits != NULL); + } + GGML_ASSERT(i_split < GGML_SCHED_MAX_SPLITS); + split = &sched->splits[i_split]; + split->backend_id = node_backend_id; + split->i_start = i; + split->n_inputs = 0; + cur_backend_id = node_backend_id; + } + + // find inputs that are not on the same backend + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + continue; + } + + const int src_backend_id = tensor_backend_id(src); + assert(src_backend_id != -1); // all inputs should be assigned by now + + if (src->flags & GGML_TENSOR_FLAG_INPUT && sched->n_copies > 1) { + size_t id = hash_id(src); + if (sched->tensor_copies[id][src_backend_id][0] == NULL) { + ggml_backend_t backend = sched->backends[src_backend_id]; + for (int c = 0; c < sched->n_copies; c++) { + struct ggml_tensor * tensor_copy; + if (c == sched->cur_copy) { + tensor_copy = src; // use the original tensor as the current copy + } else { + tensor_copy = ggml_dup_tensor_layout(sched->ctx, src); + ggml_format_name(tensor_copy, "%s#%s#%d", ggml_backend_name(backend), src->name, c); + } + if (sched->n_copies > 1) { + ggml_set_input(tensor_copy); + ggml_set_output(tensor_copy); // prevent ggml-alloc from overwriting the tensor + } + sched->tensor_copies[id][src_backend_id][c] = tensor_copy; + SET_CAUSE(tensor_copy, "4.cpy"); + } + int n_graph_inputs = sched->n_graph_inputs++; + GGML_ASSERT(n_graph_inputs < GGML_SCHED_MAX_SPLIT_INPUTS); + sched->graph_inputs[n_graph_inputs] = src; + } + } + + if (src_backend_id != node_backend_id) { + // create a copy of the input in the split's backend + const size_t id = hash_id(src); + if (sched->tensor_copies[id][cur_backend_id][0] == NULL) { + ggml_backend_t backend = sched->backends[cur_backend_id]; + for (int c = 0; c < sched->n_copies; c++) { + struct ggml_tensor * tensor_copy = ggml_dup_tensor_layout(sched->ctx, src); + ggml_format_name(tensor_copy, "%s#%s#%d", ggml_backend_name(backend), src->name, c); + if (sched->n_copies > 1) { + ggml_set_input(tensor_copy); + ggml_set_output(tensor_copy); // prevent ggml-alloc from overwriting the tensor + } + sched->tensor_copies[id][cur_backend_id][c] = tensor_copy; + SET_CAUSE(tensor_copy, "4.cpy"); + } + int n_inputs = split->n_inputs++; + GGML_ASSERT(n_inputs < GGML_SCHED_MAX_SPLIT_INPUTS); + split->inputs[n_inputs] = src; + } + node->src[j] = sched->tensor_copies[id][cur_backend_id][sched->cur_copy]; + } + } + } + split->i_end = graph->n_nodes; + sched->n_splits = i_split + 1; + } +#ifdef DEBUG_PASS4 + fprintf(stderr, "PASS 4 ASSIGNMENTS\n"); ggml_backend_sched_print_assignments(sched, graph); +#endif + + // create copies of the graph for each split + // TODO: avoid this copy + struct ggml_cgraph * graph_copy = ggml_new_graph_custom(sched->ctx, graph->n_nodes + sched->n_splits*GGML_SCHED_MAX_SPLIT_INPUTS*2, false); + for (int i = 0; i < sched->n_splits; i++) { + struct ggml_backend_sched_split * split = &sched->splits[i]; + split->graph = ggml_graph_view(graph, split->i_start, split->i_end); + + // add inputs to the graph copy so that they are allocated by ggml-alloc at the start of the split + for (int j = 0; j < split->n_inputs; j++) { + assert(graph_copy->size > (graph_copy->n_nodes + 1)); + + struct ggml_tensor * input = split->inputs[j]; + const size_t input_id = hash_id(input); + struct ggml_tensor * input_cpy = sched->tensor_copies[input_id][split->backend_id][sched->cur_copy]; + + // add a dependency to the input source so that it is not freed before the copy is done + struct ggml_tensor * input_dep = ggml_view_tensor(sched->ctx, input); + input_dep->src[0] = input; + sched->node_backend_ids[graph_copy->n_nodes] = sched->tensor_backend_id[input_id]; + graph_copy->nodes[graph_copy->n_nodes++] = input_dep; + + // add a dependency to the input copy so that it is allocated at the start of the split + sched->node_backend_ids[graph_copy->n_nodes] = split->backend_id; + graph_copy->nodes[graph_copy->n_nodes++] = input_cpy; + } + + for (int j = split->i_start; j < split->i_end; j++) { + assert(graph_copy->size > graph_copy->n_nodes); + sched->node_backend_ids[graph_copy->n_nodes] = tensor_backend_id(graph->nodes[j]); + graph_copy->nodes[graph_copy->n_nodes++] = graph->nodes[j]; + } + } + + if (sched->n_copies > 1) { + // add input copies as leafs so that they are allocated first + for (int i = 0; i < sched->n_graph_inputs; i++) { + struct ggml_tensor * input = sched->graph_inputs[i]; + size_t id = hash_id(input); + int backend_id = tensor_backend_id(input); + for (int c = 0; c < sched->n_copies; c++) { + struct ggml_tensor * input_cpy = sched->tensor_copies[id][backend_id][c]; + sched->leaf_backend_ids[graph_copy->n_leafs] = backend_id; + graph_copy->leafs[graph_copy->n_leafs++] = input_cpy; + } + } + + for (int i = 0; i < sched->n_splits; i++) { + struct ggml_backend_sched_split * split = &sched->splits[i]; + int backend_id = split->backend_id; + for (int j = 0; j < split->n_inputs; j++) { + struct ggml_tensor * input = split->inputs[j]; + size_t id = hash_id(input); + for (int c = 0; c < sched->n_copies; c++) { + struct ggml_tensor * input_cpy = sched->tensor_copies[id][backend_id][c]; + sched->leaf_backend_ids[graph_copy->n_leafs] = backend_id; + graph_copy->leafs[graph_copy->n_leafs++] = input_cpy; + } + } + } + } + + // add leafs from the original graph + for (int i = 0; i < graph->n_leafs; i++) { + struct ggml_tensor * leaf = graph->leafs[i]; + sched->leaf_backend_ids[graph_copy->n_leafs] = tensor_backend_id(leaf); + graph_copy->leafs[graph_copy->n_leafs++] = leaf; + } + + sched->graph = graph_copy; +} + +static bool ggml_backend_sched_alloc_splits(ggml_backend_sched_t sched) { + // allocate graph + if (!ggml_gallocr_alloc_graph(sched->galloc, sched->graph)) { + // the re-allocation may cause the split inputs to be moved to a different address + ggml_backend_sched_synchronize(sched); +#ifndef NDEBUG + fprintf(stderr, "%s: failed to allocate graph, reserving\n", __func__); +#endif + ggml_gallocr_reserve_n(sched->galloc, sched->graph, sched->node_backend_ids, sched->leaf_backend_ids); + if (!ggml_gallocr_alloc_graph(sched->galloc, sched->graph)) { + fprintf(stderr, "%s: failed to allocate graph\n", __func__); + return false; + } + } + + return true; +} + +static enum ggml_status ggml_backend_sched_compute_splits(ggml_backend_sched_t sched) { + struct ggml_backend_sched_split * splits = sched->splits; + + for (int i = 0; i < sched->n_splits; i++) { + struct ggml_backend_sched_split * split = &splits[i]; + int split_backend_id = split->backend_id; + ggml_backend_t split_backend = sched->backends[split_backend_id]; + + // copy the input tensors to the split backend + for (int j = 0; j < split->n_inputs; j++) { + ggml_backend_t input_backend = ggml_backend_sched_get_tensor_backend(sched, split->inputs[j]); + struct ggml_tensor * input = split->inputs[j]; + struct ggml_tensor * input_cpy = sched->tensor_copies[hash_id(input)][split_backend_id][sched->cur_copy]; + + if (input->flags & GGML_TENSOR_FLAG_INPUT) { + // inputs from the user must be copied immediately to prevent the user overwriting the data before the copy is done + if (sched->events[split_backend_id][sched->cur_copy] != NULL) { + ggml_backend_event_synchronize(sched->events[split_backend_id][sched->cur_copy]); + } else { + ggml_backend_synchronize(split_backend); + } + ggml_backend_tensor_copy(input, input_cpy); + } else { + // wait for the split backend to finish using the input before overwriting it + if (sched->events[split_backend_id][sched->cur_copy] != NULL) { + ggml_backend_event_wait(split_backend, sched->events[split_backend_id][sched->cur_copy]); + } else { + ggml_backend_synchronize(split_backend); + } + ggml_backend_tensor_copy_async(input_backend, split_backend, input, input_cpy); + } + } + + if (!sched->callback_eval) { + enum ggml_status ec = ggml_backend_graph_compute_async(split_backend, &split->graph); + if (ec != GGML_STATUS_SUCCESS) { + return ec; + } + } else { + // similar to ggml_backend_compare_graph_backend + for (int j0 = 0; j0 < split->graph.n_nodes; j0++) { + struct ggml_tensor * t = split->graph.nodes[j0]; + + // check if the user needs data from this node + bool need = sched->callback_eval(t, true, sched->callback_eval_user_data); + + int j1 = j0; + + // determine the range [j0, j1] of nodes that can be computed together + while (!need && j1 < split->graph.n_nodes - 1) { + t = split->graph.nodes[++j1]; + need = sched->callback_eval(t, true, sched->callback_eval_user_data); + } + + struct ggml_cgraph gv = ggml_graph_view(&split->graph, j0, j1 + 1); + + enum ggml_status ec = ggml_backend_graph_compute_async(split_backend, &gv); + if (ec != GGML_STATUS_SUCCESS) { + return ec; + } + + // TODO: pass backend to the callback, then the user can decide if they want to synchronize + ggml_backend_synchronize(split_backend); + + if (need && !sched->callback_eval(t, false, sched->callback_eval_user_data)) { + break; + } + + j0 = j1; + } + } + + // record the event of this copy + if (split->n_inputs > 0) { + if (sched->events[split_backend_id][sched->cur_copy] != NULL) { + ggml_backend_event_record(sched->events[split_backend_id][sched->cur_copy]); + } + } + } + + sched->cur_copy = (sched->cur_copy + 1) % sched->n_copies; + + return GGML_STATUS_SUCCESS; +} + +ggml_backend_sched_t ggml_backend_sched_new( + ggml_backend_t * backends, + ggml_backend_buffer_type_t * bufts, + int n_backends, + size_t graph_size, + bool parallel) { + GGML_ASSERT(n_backends > 0); + GGML_ASSERT(n_backends <= GGML_SCHED_MAX_BACKENDS); + GGML_ASSERT(ggml_backend_is_cpu(backends[n_backends - 1])); // last backend must be CPU + + struct ggml_backend_sched * sched = calloc(sizeof(struct ggml_backend_sched), 1); + + // initialize hash table + sched->hash_set = ggml_hash_set_new(graph_size); + sched->tensor_backend_id = calloc(sizeof(sched->tensor_backend_id[0]), sched->hash_set.size); + sched->tensor_copies = calloc(sizeof(sched->tensor_copies[0]), sched->hash_set.size); + + const size_t nodes_size = graph_size + GGML_SCHED_MAX_SPLITS*GGML_SCHED_MAX_SPLIT_INPUTS*2; + sched->node_backend_ids = calloc(sizeof(sched->node_backend_ids[0]), nodes_size); + sched->leaf_backend_ids = calloc(sizeof(sched->leaf_backend_ids[0]), nodes_size); + + sched->n_backends = n_backends; + + sched->n_copies = parallel ? GGML_SCHED_MAX_COPIES : 1; + + const int initial_splits_capacity = 16; + sched->splits = calloc(sizeof(sched->splits[0]), initial_splits_capacity); + sched->splits_capacity = initial_splits_capacity; + + for (int b = 0; b < n_backends; b++) { + sched->backends[b] = backends[b]; + sched->bufts[b] = bufts ? bufts[b] : ggml_backend_get_default_buffer_type(backends[b]); + GGML_ASSERT(ggml_backend_buft_supports_backend(sched->bufts[b], backends[b])); + if (sched->n_copies > 1) { + for (int c = 0; c < sched->n_copies; c++) { + sched->events[b][c] = ggml_backend_event_new(backends[b]); + } + } + } + + sched->galloc = ggml_gallocr_new_n(sched->bufts, n_backends); + + ggml_backend_sched_reset(sched); + + return sched; +} + +void ggml_backend_sched_free(ggml_backend_sched_t sched) { + if (sched == NULL) { + return; + } + for (int b = 0; b < sched->n_backends; b++) { + for (int c = 0; c < sched->n_copies; c++) { + ggml_backend_event_free(sched->events[b][c]); + } + } + ggml_gallocr_free(sched->galloc); + ggml_free(sched->ctx); + free(sched->splits); + free(sched->hash_set.keys); + free(sched->tensor_backend_id); + free(sched->tensor_copies); + free(sched->node_backend_ids); + free(sched->leaf_backend_ids); + free(sched); +} + +void ggml_backend_sched_reset(ggml_backend_sched_t sched) { + // reset state for the next run + size_t hash_size = sched->hash_set.size; + memset(sched->hash_set.keys, 0, sizeof(sched->hash_set.keys[0]) * hash_size); // NOLINT + memset(sched->tensor_backend_id, -1, sizeof(sched->tensor_backend_id[0]) * hash_size); + memset(sched->tensor_copies, 0, sizeof(sched->tensor_copies[0]) * hash_size); + + sched->is_reset = true; + sched->is_alloc = false; +} + +bool ggml_backend_sched_reserve(ggml_backend_sched_t sched, struct ggml_cgraph * measure_graph) { + GGML_ASSERT((int)sched->hash_set.size >= measure_graph->n_nodes); + + ggml_backend_sched_split_graph(sched, measure_graph); + + // TODO: extract this to a separate function + if (!ggml_gallocr_reserve_n(sched->galloc, sched->graph, sched->node_backend_ids, sched->leaf_backend_ids)) { + return false; + } + + ggml_backend_sched_reset(sched); + ggml_backend_sched_synchronize(sched); + + return true; +} + +bool ggml_backend_sched_alloc_graph(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + GGML_ASSERT((int)sched->hash_set.size >= graph->n_nodes); + + ggml_backend_sched_split_graph(sched, graph); + + if (!ggml_backend_sched_alloc_splits(sched)) { + return false; + } + + sched->is_alloc = true; + + return true; +} + +enum ggml_status ggml_backend_sched_graph_compute(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + enum ggml_status err = ggml_backend_sched_graph_compute_async(sched, graph); + ggml_backend_sched_synchronize(sched); + return err; +} + +enum ggml_status ggml_backend_sched_graph_compute_async(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + if (!sched->is_reset && !sched->is_alloc) { + ggml_backend_sched_reset(sched); + } + + if (!sched->is_alloc) { + if (!ggml_backend_sched_alloc_graph(sched, graph)) { + return GGML_STATUS_ALLOC_FAILED; + } + } + + return ggml_backend_sched_compute_splits(sched); +} + +void ggml_backend_sched_synchronize(ggml_backend_sched_t sched) { + for (int i = 0; i < sched->n_backends; i++) { + ggml_backend_synchronize(sched->backends[i]); + } +} + +void ggml_backend_sched_set_eval_callback(ggml_backend_sched_t sched, ggml_backend_sched_eval_callback callback, void * user_data) { + sched->callback_eval = callback; + sched->callback_eval_user_data = user_data; +} + +int ggml_backend_sched_get_n_splits(ggml_backend_sched_t sched) { + return sched->n_splits; +} + +int ggml_backend_sched_get_n_copies(ggml_backend_sched_t sched) { + return sched->n_copies; +} + +size_t ggml_backend_sched_get_buffer_size(ggml_backend_sched_t sched, ggml_backend_t backend) { + int backend_index = ggml_backend_sched_backend_id(sched, backend); + GGML_ASSERT(backend_index >= 0 && backend_index < sched->n_backends); + + return ggml_gallocr_get_buffer_size(sched->galloc, backend_index); +} + +void ggml_backend_sched_set_tensor_backend(ggml_backend_sched_t sched, struct ggml_tensor * node, ggml_backend_t backend) { + int backend_index = ggml_backend_sched_backend_id(sched, backend); + GGML_ASSERT(backend_index >= 0 && backend_index < sched->n_backends); + tensor_backend_id(node) = backend_index; +} + +ggml_backend_t ggml_backend_sched_get_tensor_backend(ggml_backend_sched_t sched, struct ggml_tensor * node) { + int backend_index = tensor_backend_id(node); + if (backend_index == -1) { + return NULL; + } + return sched->backends[backend_index]; +} + +// utils + +void ggml_backend_view_init(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + GGML_ASSERT(tensor->buffer == NULL); + GGML_ASSERT(tensor->view_src != NULL); + GGML_ASSERT(tensor->view_src->buffer != NULL); + GGML_ASSERT(tensor->view_src->data != NULL); + + tensor->buffer = buffer; + tensor->data = (char *)tensor->view_src->data + tensor->view_offs; + tensor->backend = tensor->view_src->backend; + ggml_backend_buffer_init_tensor(buffer, tensor); +} + +void ggml_backend_tensor_alloc(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor, void * addr) { + GGML_ASSERT(tensor->buffer == NULL); + GGML_ASSERT(tensor->data == NULL); + GGML_ASSERT(tensor->view_src == NULL); + GGML_ASSERT(addr >= ggml_backend_buffer_get_base(buffer)); + GGML_ASSERT((char *)addr + ggml_backend_buffer_get_alloc_size(buffer, tensor) <= + (char *)ggml_backend_buffer_get_base(buffer) + ggml_backend_buffer_get_size(buffer)); + + tensor->buffer = buffer; + tensor->data = addr; + ggml_backend_buffer_init_tensor(buffer, tensor); +} + +static struct ggml_tensor * graph_copy_dup_tensor(struct ggml_hash_set hash_set, struct ggml_tensor ** node_copies, + struct ggml_context * ctx_allocated, struct ggml_context * ctx_unallocated, struct ggml_tensor * src) { + + GGML_ASSERT(src != NULL); + GGML_ASSERT(src->data && "graph must be allocated"); + + size_t id = ggml_hash_insert(hash_set, src); + if (id == GGML_HASHTABLE_ALREADY_EXISTS) { + return node_copies[ggml_hash_find(hash_set, src)]; + } + + struct ggml_tensor * dst = ggml_dup_tensor_layout(src->data && !src->view_src ? ctx_allocated : ctx_unallocated, src); + if (src->view_src != NULL) { + dst->view_src = graph_copy_dup_tensor(hash_set, node_copies, ctx_allocated, ctx_unallocated, src->view_src); + dst->view_offs = src->view_offs; + } + dst->op = src->op; + memcpy(dst->op_params, src->op_params, sizeof(dst->op_params)); + ggml_set_name(dst, src->name); + + // copy src + for (int i = 0; i < GGML_MAX_SRC; i++) { + struct ggml_tensor * s = src->src[i]; + if (s == NULL) { + continue; + } + dst->src[i] = graph_copy_dup_tensor(hash_set, node_copies, ctx_allocated, ctx_unallocated, s); + } + + node_copies[id] = dst; + return dst; +} + +static void graph_copy_init_tensor(struct ggml_hash_set hash_set, struct ggml_tensor ** node_copies, bool * node_init, struct ggml_tensor * src) { + size_t id = ggml_hash_find(hash_set, src); + if (node_init[id]) { + return; + } + node_init[id] = true; + + struct ggml_tensor * dst = node_copies[id]; + if (dst->view_src != NULL) { + graph_copy_init_tensor(hash_set, node_copies, node_init, src->view_src); + ggml_backend_view_init(dst->view_src->buffer, dst); + } + else { + ggml_backend_tensor_copy(src, dst); + } + + // init src + for (int i = 0; i < GGML_MAX_SRC; i++) { + struct ggml_tensor * s = src->src[i]; + if (s == NULL) { + continue; + } + graph_copy_init_tensor(hash_set, node_copies, node_init, s); + } +} + +struct ggml_backend_graph_copy ggml_backend_graph_copy(ggml_backend_t backend, struct ggml_cgraph * graph) { + struct ggml_hash_set hash_set = { + /* .size = */ graph->visited_hash_table.size, + /* .keys = */ calloc(sizeof(hash_set.keys[0]), graph->visited_hash_table.size) // NOLINT + }; + struct ggml_tensor ** node_copies = calloc(sizeof(node_copies[0]), hash_set.size); // NOLINT + bool * node_init = calloc(sizeof(node_init[0]), hash_set.size); + + struct ggml_init_params params = { + /* .mem_size = */ ggml_tensor_overhead()*hash_set.size + ggml_graph_overhead_custom(graph->size, false), + /* .mem_buffer = */ NULL, + /* .no_alloc = */ true + }; + + struct ggml_context * ctx_allocated = ggml_init(params); + struct ggml_context * ctx_unallocated = ggml_init(params); + + if (ctx_allocated == NULL || ctx_unallocated == NULL) { + fprintf(stderr, "failed to allocate context for graph copy\n"); + free(hash_set.keys); + free(node_copies); + free(node_init); + ggml_free(ctx_allocated); + ggml_free(ctx_unallocated); + return (struct ggml_backend_graph_copy) { + /* .buffer = */ NULL, + /* .ctx_allocated = */ NULL, + /* .ctx_unallocated = */ NULL, + /* .graph = */ NULL, + }; + } + + // dup nodes + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + graph_copy_dup_tensor(hash_set, node_copies, ctx_allocated, ctx_unallocated, node); + } + + // allocate nodes + ggml_backend_buffer_t buffer = ggml_backend_alloc_ctx_tensors(ctx_allocated, backend); + if (buffer == NULL) { + fprintf(stderr, "failed to allocate buffer for graph copy\n"); + free(hash_set.keys); + free(node_copies); + free(node_init); + ggml_free(ctx_allocated); + ggml_free(ctx_unallocated); + return (struct ggml_backend_graph_copy) { + /* .buffer = */ NULL, + /* .ctx_allocated = */ NULL, + /* .ctx_unallocated = */ NULL, + /* .graph = */ NULL, + }; + } + + //printf("copy buffer size: %zu MB\n", ggml_backend_buffer_get_size(buffer) / 1024 / 1024); + + // copy data and init views + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + graph_copy_init_tensor(hash_set, node_copies, node_init, node); + } + + // build graph copy + struct ggml_cgraph * graph_copy = ggml_new_graph_custom(ctx_allocated, graph->size, false); + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + struct ggml_tensor * node_copy = node_copies[ggml_hash_find(hash_set, node)]; + graph_copy->nodes[i] = node_copy; + } + graph_copy->n_nodes = graph->n_nodes; + + free(hash_set.keys); + free(node_copies); + free(node_init); + + return (struct ggml_backend_graph_copy) { + /* .buffer = */ buffer, + /* .ctx_allocated = */ ctx_allocated, + /* .ctx_unallocated = */ ctx_unallocated, + /* .graph = */ graph_copy, + }; +} + +void ggml_backend_graph_copy_free(struct ggml_backend_graph_copy copy) { + ggml_backend_buffer_free(copy.buffer); + ggml_free(copy.ctx_allocated); + ggml_free(copy.ctx_unallocated); +} + +bool ggml_backend_compare_graph_backend(ggml_backend_t backend1, ggml_backend_t backend2, struct ggml_cgraph * graph, ggml_backend_eval_callback callback, void * user_data) { + struct ggml_backend_graph_copy copy = ggml_backend_graph_copy(backend2, graph); + if (copy.buffer == NULL) { + return false; + } + + struct ggml_cgraph * g1 = graph; + struct ggml_cgraph * g2 = copy.graph; + + assert(g1->n_nodes == g2->n_nodes); + + for (int i = 0; i < g1->n_nodes; i++) { + //printf("eval %d/%d\n", i, g1->n_nodes); + struct ggml_tensor * t1 = g1->nodes[i]; + struct ggml_tensor * t2 = g2->nodes[i]; + + assert(t1->op == t2->op && ggml_are_same_layout(t1, t2)); + + struct ggml_cgraph g1v = ggml_graph_view(g1, i, i + 1); + struct ggml_cgraph g2v = ggml_graph_view(g2, i, i + 1); + + ggml_backend_graph_compute(backend1, &g1v); + ggml_backend_graph_compute(backend2, &g2v); + + if (ggml_is_view_op(t1->op)) { + continue; + } + + // compare results, calculate rms etc + if (!callback(i, t1, t2, user_data)) { + break; + } + } + + ggml_backend_graph_copy_free(copy); + + return true; +} diff --git a/bindings/ruby/ext/ggml-backend.h b/bindings/ruby/ext/ggml-backend.h new file mode 100644 index 0000000000000000000000000000000000000000..744b6a77457d730a1abdb849d994f7c3d5cc81fe --- /dev/null +++ b/bindings/ruby/ext/ggml-backend.h @@ -0,0 +1,233 @@ +#pragma once + +#include "ggml.h" +#include "ggml-alloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct ggml_backend_buffer_type * ggml_backend_buffer_type_t; + typedef struct ggml_backend_buffer * ggml_backend_buffer_t; + typedef struct ggml_backend_event * ggml_backend_event_t; + typedef struct ggml_backend * ggml_backend_t; + typedef void * ggml_backend_graph_plan_t; + + // + // Backend buffer + // + + // buffer type + GGML_API const char * ggml_backend_buft_name (ggml_backend_buffer_type_t buft); + GGML_API GGML_CALL ggml_backend_buffer_t ggml_backend_buft_alloc_buffer (ggml_backend_buffer_type_t buft, size_t size); + GGML_API size_t ggml_backend_buft_get_alignment (ggml_backend_buffer_type_t buft); + GGML_API size_t ggml_backend_buft_get_max_size (ggml_backend_buffer_type_t buft); + GGML_API GGML_CALL size_t ggml_backend_buft_get_alloc_size (ggml_backend_buffer_type_t buft, struct ggml_tensor * tensor); + GGML_API bool ggml_backend_buft_supports_backend(ggml_backend_buffer_type_t buft, ggml_backend_t backend); + GGML_API bool ggml_backend_buft_is_host (ggml_backend_buffer_type_t buft); + + // buffer + enum ggml_backend_buffer_usage { + GGML_BACKEND_BUFFER_USAGE_ANY = 0, + GGML_BACKEND_BUFFER_USAGE_WEIGHTS = 1, + }; + + GGML_API const char * ggml_backend_buffer_name (ggml_backend_buffer_t buffer); + GGML_API void ggml_backend_buffer_free (ggml_backend_buffer_t buffer); + GGML_API void * ggml_backend_buffer_get_base (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_size (ggml_backend_buffer_t buffer); + GGML_API GGML_CALL void ggml_backend_buffer_init_tensor (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + GGML_API size_t ggml_backend_buffer_get_alignment (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_max_size (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_alloc_size(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + GGML_API void ggml_backend_buffer_clear (ggml_backend_buffer_t buffer, uint8_t value); + GGML_API bool ggml_backend_buffer_is_host (ggml_backend_buffer_t buffer); + GGML_API void ggml_backend_buffer_set_usage (ggml_backend_buffer_t buffer, enum ggml_backend_buffer_usage usage); + GGML_API ggml_backend_buffer_type_t ggml_backend_buffer_get_type (ggml_backend_buffer_t buffer); + GGML_API void ggml_backend_buffer_reset (ggml_backend_buffer_t buffer); + + // + // Backend + // + + GGML_API ggml_guid_t ggml_backend_guid(ggml_backend_t backend); + GGML_API const char * ggml_backend_name(ggml_backend_t backend); + GGML_API void ggml_backend_free(ggml_backend_t backend); + + GGML_API ggml_backend_buffer_type_t ggml_backend_get_default_buffer_type(ggml_backend_t backend); + GGML_API ggml_backend_buffer_t ggml_backend_alloc_buffer(ggml_backend_t backend, size_t size); + GGML_API size_t ggml_backend_get_alignment(ggml_backend_t backend); + GGML_API size_t ggml_backend_get_max_size(ggml_backend_t backend); + + GGML_API void ggml_backend_tensor_set_async(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + GGML_API void ggml_backend_tensor_get_async(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + + GGML_API GGML_CALL void ggml_backend_tensor_set( struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + GGML_API GGML_CALL void ggml_backend_tensor_get(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + + GGML_API void ggml_backend_synchronize(ggml_backend_t backend); + + GGML_API ggml_backend_graph_plan_t ggml_backend_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph); + GGML_API void ggml_backend_graph_plan_free (ggml_backend_t backend, ggml_backend_graph_plan_t plan); + + GGML_API enum ggml_status ggml_backend_graph_plan_compute (ggml_backend_t backend, ggml_backend_graph_plan_t plan); + GGML_API enum ggml_status ggml_backend_graph_compute (ggml_backend_t backend, struct ggml_cgraph * cgraph); + GGML_API enum ggml_status ggml_backend_graph_compute_async(ggml_backend_t backend, struct ggml_cgraph * cgraph); + GGML_API bool ggml_backend_supports_op(ggml_backend_t backend, const struct ggml_tensor * op); + GGML_API bool ggml_backend_offload_op(ggml_backend_t backend, const struct ggml_tensor * op); + + // tensor copy between different backends + GGML_API void ggml_backend_tensor_copy(struct ggml_tensor * src, struct ggml_tensor * dst); + + // asynchronous copy + // the copy is performed after all the currently queued operations in backend_src + // backend_dst will wait for the copy to complete before performing other operations + // automatic fallback to sync copy if async is not supported + GGML_API void ggml_backend_tensor_copy_async(ggml_backend_t backend_src, ggml_backend_t backend_dst, struct ggml_tensor * src, struct ggml_tensor * dst); + + // events + GGML_API ggml_backend_event_t ggml_backend_event_new (ggml_backend_t backend); + GGML_API void ggml_backend_event_free (ggml_backend_event_t event); + GGML_API void ggml_backend_event_record (ggml_backend_event_t event); + GGML_API void ggml_backend_event_synchronize(ggml_backend_event_t event); + GGML_API void ggml_backend_event_wait (ggml_backend_t backend, ggml_backend_event_t event); // wait async on event + + // + // CPU backend + // + + GGML_API ggml_backend_t ggml_backend_cpu_init(void); + + GGML_API GGML_CALL bool ggml_backend_is_cpu (ggml_backend_t backend); + GGML_API void ggml_backend_cpu_set_n_threads (ggml_backend_t backend_cpu, int n_threads); + GGML_API void ggml_backend_cpu_set_abort_callback(ggml_backend_t backend_cpu, ggml_abort_callback abort_callback, void * abort_callback_data); + + // Create a backend buffer from an existing pointer + GGML_API GGML_CALL ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(void * ptr, size_t size); + + GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_cpu_buffer_type(void); + +#ifdef GGML_USE_CPU_HBM + GGML_API ggml_backend_buffer_type_t ggml_backend_cpu_hbm_buffer_type(void); +#endif + + // + // Backend registry + // + + // The backend registry is a registry of all the available backends, and allows initializing backends in a generic way + + GGML_API size_t ggml_backend_reg_get_count(void); + GGML_API size_t ggml_backend_reg_find_by_name(const char * name); + GGML_API ggml_backend_t ggml_backend_reg_init_backend_from_str(const char * backend_str); // str is name[:params] + GGML_API const char * ggml_backend_reg_get_name(size_t i); + GGML_API ggml_backend_t ggml_backend_reg_init_backend(size_t i, const char * params); // params is backend-specific + GGML_API ggml_backend_buffer_type_t ggml_backend_reg_get_default_buffer_type(size_t i); + GGML_API ggml_backend_buffer_t ggml_backend_reg_alloc_buffer(size_t i, size_t size); + + // + // Backend scheduler + // + + // The backend scheduler allows for multiple backends to be used together + // Handles compute buffer allocation, assignment of tensors to backends, and copying of tensors between backends + // The backends are selected based on: + // - the backend that supports the operation + // - the location of the pre-allocated tensors (e.g. the weights) + /* + Example usage: + + // operations that use tensors allocated in a buffer with USAGE_WEIGHTS will be assigned + // preferrably to run on the same backend as the buffer + ggml_backend_buffer_set_usage(buf_weights, GGML_BACKEND_BUFFER_USAGE_WEIGHTS); + + sched = ggml_backend_sched_new({backend_gpu, backend_gpu2, backend_cpu}, NULL, num_backends, GGML_DEFAULT_GRAPH_SIZE, false); + + // initialize buffers from a max size graph (optional) + reserve_graph = build_graph(sched, max_batch_size); + + // manually assign nodes to a backend (optional, should not be needed in most cases) + struct ggml_tensor * node = ggml_mul_mat(ctx, ...); + ggml_backend_sched_set_tensor_backend(sched, node, backend_gpu); + + ggml_backend_sched_reserve(sched, reserve_graph); + + // compute + graph = build_graph(sched); + ggml_backend_sched_graph_compute(sched, graph); + + // if there are graph inputs: + ggml_backend_sched_reset(sched); + ggml_backend_sched_alloc_graph(sched, graph); + ggml_backend_tensor_set(input_tensor, ...); + ggml_backend_sched_graph_compute(sched, graph); + } + */ + + struct ggml_backend_sched; + typedef struct ggml_backend_sched * ggml_backend_sched_t; + + // when ask == true, the scheduler wants to know if the user wants to observe this node + // this allows the scheduler to batch nodes together in order to evaluate them in a single call + // + // when ask == false, the scheduler is passing the node tensor to the user for observation + // if the user returns false, the scheduler will cancel the graph compute + // + typedef bool (*ggml_backend_sched_eval_callback)(struct ggml_tensor * t, bool ask, void * user_data); + + // Initialize a backend scheduler + GGML_API ggml_backend_sched_t ggml_backend_sched_new(ggml_backend_t * backends, ggml_backend_buffer_type_t * bufts, int n_backends, size_t graph_size, bool parallel); + GGML_API void ggml_backend_sched_free(ggml_backend_sched_t sched); + + // Initialize backend buffers from a measure graph + GGML_API bool ggml_backend_sched_reserve(ggml_backend_sched_t sched, struct ggml_cgraph * measure_graph); + + // Get the number of splits of the last graph + GGML_API int ggml_backend_sched_get_n_splits(ggml_backend_sched_t sched); + GGML_API int ggml_backend_sched_get_n_copies(ggml_backend_sched_t sched); + + GGML_API size_t ggml_backend_sched_get_buffer_size(ggml_backend_sched_t sched, ggml_backend_t backend); + + GGML_API void ggml_backend_sched_set_tensor_backend(ggml_backend_sched_t sched, struct ggml_tensor * node, ggml_backend_t backend); + GGML_API ggml_backend_t ggml_backend_sched_get_tensor_backend(ggml_backend_sched_t sched, struct ggml_tensor * node); + + // Allocate and compute graph on the backend scheduler + GGML_API bool ggml_backend_sched_alloc_graph(ggml_backend_sched_t sched, struct ggml_cgraph * graph); + GGML_API enum ggml_status ggml_backend_sched_graph_compute(ggml_backend_sched_t sched, struct ggml_cgraph * graph); + GGML_API enum ggml_status ggml_backend_sched_graph_compute_async(ggml_backend_sched_t sched, struct ggml_cgraph * graph); + GGML_API void ggml_backend_sched_synchronize(ggml_backend_sched_t sched); + + // Reset all assignments and allocators - must be called before changing the node backends + GGML_API void ggml_backend_sched_reset(ggml_backend_sched_t sched); + + // Set a callback to be called for each resulting node during graph compute + GGML_API void ggml_backend_sched_set_eval_callback(ggml_backend_sched_t sched, ggml_backend_sched_eval_callback callback, void * user_data); + + // + // Utils + // + + struct ggml_backend_graph_copy { + ggml_backend_buffer_t buffer; + struct ggml_context * ctx_allocated; + struct ggml_context * ctx_unallocated; + struct ggml_cgraph * graph; + }; + + // Copy a graph to a different backend + GGML_API struct ggml_backend_graph_copy ggml_backend_graph_copy(ggml_backend_t backend, struct ggml_cgraph * graph); + GGML_API void ggml_backend_graph_copy_free(struct ggml_backend_graph_copy copy); + + typedef bool (*GGML_CALL ggml_backend_eval_callback)(int node_index, struct ggml_tensor * t1, struct ggml_tensor * t2, void * user_data); + + // Compare the output of two backends + GGML_API bool ggml_backend_compare_graph_backend(ggml_backend_t backend1, ggml_backend_t backend2, struct ggml_cgraph * graph, ggml_backend_eval_callback callback, void * user_data); + + // Tensor initialization + GGML_API void ggml_backend_tensor_alloc(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor, void * addr); + GGML_API void ggml_backend_view_init(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-common.h b/bindings/ruby/ext/ggml-common.h new file mode 100644 index 0000000000000000000000000000000000000000..43c7978a0982d1852f8d4751883cebee18f2862c --- /dev/null +++ b/bindings/ruby/ext/ggml-common.h @@ -0,0 +1,1853 @@ +#ifndef GGML_COMMON_DECL + +#if defined(GGML_COMMON_DECL_C) +#include + +typedef uint16_t ggml_half; +typedef uint32_t ggml_half2; + +#define GGML_COMMON_AGGR + +#define GGML_COMMON_DECL +#elif defined(GGML_COMMON_DECL_METAL) +#include + +typedef half ggml_half; +typedef half2 ggml_half2; + +#define GGML_COMMON_AGGR + +#define GGML_COMMON_DECL +#elif defined(GGML_COMMON_DECL_CUDA) +#include +#include + +typedef half ggml_half; +typedef half2 ggml_half2; + +#define GGML_COMMON_AGGR data + +#define GGML_COMMON_DECL +#elif defined(GGML_COMMON_DECL_HIP) +#include +#include + +typedef half ggml_half; +typedef half2 ggml_half2; + +#define GGML_COMMON_AGGR data + +#define GGML_COMMON_DECL +#elif defined(GGML_COMMON_DECL_SYCL) +#include +#include + +typedef sycl::half ggml_half; +typedef sycl::half2 ggml_half2; + +#define GGML_COMMON_AGGR data + +#define GGML_COMMON_DECL +#endif + +#if defined(GGML_COMMON_DECL) + +#ifndef __cplusplus +#ifndef static_assert +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201100L) +#define static_assert(cond, msg) _Static_assert(cond, msg) +#else +#define static_assert(cond, msg) struct global_scope_noop_trick +#endif +#endif +#endif // __cplusplus + +// QK = number of values after dequantization +// QK_K = super-block size + +#ifdef GGML_QKK_64 +#define QK_K 64 +#define K_SCALE_SIZE 4 +#else +#define QK_K 256 +#define K_SCALE_SIZE 12 +#endif // GGML_QKK_64 + +#if defined(GGML_COMMON_DECL_CUDA) || defined(GGML_COMMON_DECL_HIP) || defined(GGML_COMMON_DECL_SYCL) +// QR = QK / number of values before dequantization +// QI = number of 32 bit integers before dequantization + +#define QI4_0 (QK4_0 / (4 * QR4_0)) +#define QR4_0 2 + +#define QI4_1 (QK4_1 / (4 * QR4_1)) +#define QR4_1 2 + +#define QI5_0 (QK5_0 / (4 * QR5_0)) +#define QR5_0 2 + +#define QI5_1 (QK5_1 / (4 * QR5_1)) +#define QR5_1 2 + +#define QI8_0 (QK8_0 / (4 * QR8_0)) +#define QR8_0 1 + +#define QI8_1 (QK8_1 / (4 * QR8_1)) +#define QR8_1 1 + +#define QI2_K (QK_K / (4*QR2_K)) +#define QR2_K 4 + +#define QI3_K (QK_K / (4*QR3_K)) +#define QR3_K 4 + +#define QI4_K (QK_K / (4*QR4_K)) +#define QR4_K 2 + +#define QI5_K (QK_K / (4*QR5_K)) +#define QR5_K 2 + +#define QI6_K (QK_K / (4*QR6_K)) +#define QR6_K 2 + +#define QI2_XXS (QK_K / (4*QR2_XXS)) +#define QR2_XXS 8 + +#define QI2_XS (QK_K / (4*QR2_XS)) +#define QR2_XS 8 + +#define QI2_S (QK_K / (4*QR2_S)) +#define QR2_S 8 + +#define QI3_XXS (QK_K / (4*QR3_XXS)) +#define QR3_XXS 8 + +#define QI3_XS (QK_K / (4*QR3_XS)) +#define QR3_XS 8 + +#define QI1_S (QK_K / (4*QR1_S)) +#define QR1_S 8 + +#define QI4_NL (QK4_NL / (4*QR4_NL)) +#define QR4_NL 2 + +#if QK_K == 64 +#define QI4_XS QI4_NL +#define QR4_XS QR4_NL +#else +#define QI4_XS (QK_K / (4*QR4_XS)) +#define QR4_XS 8 +#endif + +#endif // GGML_COMMON_DECL_CUDA || GGML_COMMON_DECL_HIP + +#define QK4_0 32 +typedef struct { + ggml_half d; // delta + uint8_t qs[QK4_0 / 2]; // nibbles / quants +} block_q4_0; +static_assert(sizeof(block_q4_0) == sizeof(ggml_half) + QK4_0 / 2, "wrong q4_0 block size/padding"); + +#define QK4_1 32 +typedef struct { + union { + struct { + ggml_half d; // delta + ggml_half m; // min + } GGML_COMMON_AGGR; + ggml_half2 dm; + }; + uint8_t qs[QK4_1 / 2]; // nibbles / quants +} block_q4_1; +static_assert(sizeof(block_q4_1) == 2 * sizeof(ggml_half) + QK4_1 / 2, "wrong q4_1 block size/padding"); + +#define QK5_0 32 +typedef struct { + ggml_half d; // delta + uint8_t qh[4]; // 5-th bit of quants + uint8_t qs[QK5_0 / 2]; // nibbles / quants +} block_q5_0; +static_assert(sizeof(block_q5_0) == sizeof(ggml_half) + sizeof(uint32_t) + QK5_0 / 2, "wrong q5_0 block size/padding"); + +#define QK5_1 32 +typedef struct { + union { + struct { + ggml_half d; // delta + ggml_half m; // min + } GGML_COMMON_AGGR; + ggml_half2 dm; + }; + uint8_t qh[4]; // 5-th bit of quants + uint8_t qs[QK5_1 / 2]; // nibbles / quants +} block_q5_1; +static_assert(sizeof(block_q5_1) == 2 * sizeof(ggml_half) + sizeof(uint32_t) + QK5_1 / 2, "wrong q5_1 block size/padding"); + +#define QK8_0 32 +typedef struct { + ggml_half d; // delta + int8_t qs[QK8_0]; // quants +} block_q8_0; +static_assert(sizeof(block_q8_0) == sizeof(ggml_half) + QK8_0, "wrong q8_0 block size/padding"); + +#define QK8_1 32 +typedef struct { + union { + struct { + ggml_half d; // delta + ggml_half s; // d * sum(qs[i]) + } GGML_COMMON_AGGR; + ggml_half2 ds; + }; + int8_t qs[QK8_1]; // quants +} block_q8_1; +static_assert(sizeof(block_q8_1) == 2*sizeof(ggml_half) + QK8_1, "wrong q8_1 block size/padding"); + +// +// Super-block quantization structures +// + +// 2-bit quantization +// weight is represented as x = a * q + b +// 16 blocks of 16 elements each +// Effectively 2.625 bits per weight +typedef struct { + uint8_t scales[QK_K/16]; // scales and mins, quantized with 4 bits + uint8_t qs[QK_K/4]; // quants + union { + struct { + ggml_half d; // super-block scale for quantized scales + ggml_half dmin; // super-block scale for quantized mins + } GGML_COMMON_AGGR; + ggml_half2 dm; + }; +} block_q2_K; +static_assert(sizeof(block_q2_K) == 2*sizeof(ggml_half) + QK_K/16 + QK_K/4, "wrong q2_K block size/padding"); + +// 3-bit quantization +// weight is represented as x = a * q +// 16 blocks of 16 elements each +// Effectively 3.4375 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + uint8_t hmask[QK_K/8]; // quants - high bit + uint8_t qs[QK_K/4]; // quants - low 2 bits + uint8_t scales[2]; + ggml_half d; // super-block scale +} block_q3_K; +static_assert(sizeof(block_q3_K) == sizeof(ggml_half) + QK_K / 4 + QK_K / 8 + 2, "wrong q3_K block size/padding"); +#else +typedef struct { + uint8_t hmask[QK_K/8]; // quants - high bit + uint8_t qs[QK_K/4]; // quants - low 2 bits + uint8_t scales[12]; // scales, quantized with 6 bits + ggml_half d; // super-block scale +} block_q3_K; +static_assert(sizeof(block_q3_K) == sizeof(ggml_half) + QK_K / 4 + QK_K / 8 + 12, "wrong q3_K block size/padding"); +#endif + +// 4-bit quantization +// 8 blocks of 32 elements each +// weight is represented as x = a * q + b +// Effectively 4.5 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + ggml_half d[2]; // super-block scales/mins + uint8_t scales[2]; // 4-bit block scales/mins + uint8_t qs[QK_K/2]; // 4--bit quants +} block_q4_K; +static_assert(sizeof(block_q4_K) == 2*sizeof(ggml_half) + QK_K/2 + 2, "wrong q4_K block size/padding"); +#else +typedef struct { + union { + struct { + ggml_half d; // super-block scale for quantized scales + ggml_half dmin; // super-block scale for quantized mins + } GGML_COMMON_AGGR; + ggml_half2 dm; + }; + uint8_t scales[K_SCALE_SIZE]; // scales and mins, quantized with 6 bits + uint8_t qs[QK_K/2]; // 4--bit quants +} block_q4_K; +static_assert(sizeof(block_q4_K) == 2*sizeof(ggml_half) + K_SCALE_SIZE + QK_K/2, "wrong q4_K block size/padding"); +#endif + +// 5-bit quantization +// 8 blocks of 32 elements each +// weight is represented as x = a * q + b +// Effectively 5.5 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + ggml_half d; // super-block scale + int8_t scales[QK_K/16]; // 8-bit block scales + uint8_t qh[QK_K/8]; // quants, high bit + uint8_t qs[QK_K/2]; // quants, low 4 bits +} block_q5_K; +static_assert(sizeof(block_q5_K) == sizeof(ggml_half) + QK_K/2 + QK_K/8 + QK_K/16, "wrong q5_K block size/padding"); +#else +typedef struct { + union { + struct { + ggml_half d; // super-block scale for quantized scales + ggml_half dmin; // super-block scale for quantized mins + } GGML_COMMON_AGGR; + ggml_half2 dm; + }; + uint8_t scales[K_SCALE_SIZE]; // scales and mins, quantized with 6 bits + uint8_t qh[QK_K/8]; // quants, high bit + uint8_t qs[QK_K/2]; // quants, low 4 bits +} block_q5_K; +static_assert(sizeof(block_q5_K) == 2*sizeof(ggml_half) + K_SCALE_SIZE + QK_K/2 + QK_K/8, "wrong q5_K block size/padding"); +#endif + +// 6-bit quantization +// weight is represented as x = a * q +// 16 blocks of 16 elements each +// Effectively 6.5625 bits per weight +typedef struct { + uint8_t ql[QK_K/2]; // quants, lower 4 bits + uint8_t qh[QK_K/4]; // quants, upper 2 bits + int8_t scales[QK_K/16]; // scales, quantized with 8 bits + ggml_half d; // super-block scale +} block_q6_K; +static_assert(sizeof(block_q6_K) == sizeof(ggml_half) + QK_K / 16 + 3*QK_K/4, "wrong q6_K block size/padding"); + +// This is only used for intermediate quantization and dot products +typedef struct { + float d; // delta + int8_t qs[QK_K]; // quants + int16_t bsums[QK_K/16]; // sum of quants in groups of 16 +} block_q8_K; +static_assert(sizeof(block_q8_K) == sizeof(float) + QK_K + QK_K/16*sizeof(int16_t), "wrong q8_K block size/padding"); + +// (Almost) "true" 2-bit quantization. +// Due to the need to use blocks as per ggml design, it ends up using +// 2.0625 bpw because of the 16-bit scale for each block of 256. +typedef struct { + ggml_half d; + uint16_t qs[QK_K/8]; +} block_iq2_xxs; +static_assert(sizeof(block_iq2_xxs) == sizeof(ggml_half) + QK_K/8*sizeof(uint16_t), "wrong iq2_xxs block size/padding"); + +// 2.3125 bpw quants +typedef struct { + ggml_half d; + uint16_t qs[QK_K/8]; + uint8_t scales[QK_K/32]; +} block_iq2_xs; +static_assert(sizeof(block_iq2_xs) == sizeof(ggml_half) + QK_K/8*sizeof(uint16_t) + QK_K/32, "wrong iq2_xs block size/padding"); + +// 2.5625 bpw quants +typedef struct { + ggml_half d; + uint8_t qs[QK_K/4]; + uint8_t qh[QK_K/32]; + uint8_t scales[QK_K/32]; +} block_iq2_s; +static_assert(sizeof(block_iq2_s) == sizeof(ggml_half) + QK_K/4 + QK_K/16, "wrong iq2_s block size/padding"); + +// (Almost) "true" 3-bit quantization. +// Due to the need to use blocks as per ggml design, it ends up using +// 3.0625 bpw because of the 16-bit scale for each block of 256. +typedef struct { + ggml_half d; + uint8_t qs[3*QK_K/8]; +} block_iq3_xxs; +static_assert(sizeof(block_iq3_xxs) == sizeof(ggml_half) + 3*(QK_K/8), "wrong iq3_xxs block size/padding"); + +// 3.4375 bpw +#if QK_K == 64 +#define IQ3S_N_SCALE 2 +#else +#define IQ3S_N_SCALE QK_K/64 +#endif +typedef struct { + ggml_half d; + uint8_t qs[QK_K/4]; + uint8_t qh[QK_K/32]; + uint8_t signs[QK_K/8]; + uint8_t scales[IQ3S_N_SCALE]; +} block_iq3_s; +static_assert(sizeof(block_iq3_s) == sizeof(ggml_half) + 13*(QK_K/32) + IQ3S_N_SCALE, "wrong iq3_s block size/padding"); + +typedef struct { + ggml_half d; + uint8_t qs[QK_K/8]; + uint16_t qh[QK_K/32]; +} block_iq1_s; +static_assert(sizeof(block_iq1_s) == sizeof(ggml_half) + QK_K/8 + QK_K/16, "wrong iq1_s block size/padding"); + +// 1.75 bpw +typedef struct { + uint8_t qs[QK_K/8]; // grid index, low 8 bits + uint8_t qh[QK_K/16]; // grid index, high 3 bits + grid shift bit (for two groups of 8) +#if QK_K == 64 + ggml_half d; +#endif + uint8_t scales[QK_K/32]; // 3-bit block scales (4-bit if QK_K == 64) +} block_iq1_m; +#if QK_K == 64 +static_assert(sizeof(block_iq1_m) == QK_K/8 + QK_K/16 + QK_K/32 + sizeof(ggml_half), "wrong iq1_m block size/padding"); +#else +static_assert(sizeof(block_iq1_m) == QK_K/8 + QK_K/16 + QK_K/32, "wrong iq1_m block size/padding"); +#endif + +// Used by IQ1_M quants +typedef union { + ggml_half f16; + uint16_t u16; +} iq1m_scale_t; + +// Non-linear quants +#define QK4_NL 32 +typedef struct { + ggml_half d; + uint8_t qs[QK4_NL/2]; +} block_iq4_nl; +static_assert(sizeof(block_iq4_nl) == sizeof(ggml_half) + QK4_NL/2, "wrong iq4_nl block size/padding"); + +#if QK_K == 64 +#define block_iq4_xs block_iq4_nl +#else +typedef struct { + ggml_half d; + uint16_t scales_h; + uint8_t scales_l[QK_K/64]; + uint8_t qs[QK_K/2]; +} block_iq4_xs; +static_assert(sizeof(block_iq4_xs) == sizeof(ggml_half) + sizeof(uint16_t) + QK_K/64 + QK_K/2, "wrong iq4_xs block size/padding"); +#endif + +#endif // GGML_COMMON_DECL +#endif // GGML_COMMON_DECL + +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GGML_COMMON_IMPL + +#if defined(GGML_COMMON_IMPL_C) +#include + +#define GGML_TABLE_BEGIN(type, name, size) static const type name[size] = { +#define GGML_TABLE_END() }; + +#define GGML_COMMON_IMPL +#elif defined(GGML_COMMON_IMPL_METAL) +#include + +#define GGML_TABLE_BEGIN(type, name, size) static const constant type name[size] = { +#define GGML_TABLE_END() }; + +#define GGML_COMMON_IMPL +#elif defined(GGML_COMMON_IMPL_CUDA) || defined(GGML_COMMON_IMPL_HIP) +#include + +#define GGML_TABLE_BEGIN(type, name, size) static const __device__ type name[size] = { +#define GGML_TABLE_END() }; + +#define GGML_COMMON_IMPL +#elif defined(GGML_COMMON_IMPL_SYCL) + +#include + +#define GGML_TABLE_BEGIN(type, name, size) static const type name[size] = { +#define GGML_TABLE_END() }; + +#define GGML_COMMON_IMPL +#endif + +#if defined(GGML_COMMON_IMPL) + +GGML_TABLE_BEGIN(uint8_t, kmask_iq2xs, 8) + 1, 2, 4, 8, 16, 32, 64, 128 +GGML_TABLE_END() + +GGML_TABLE_BEGIN(uint8_t, ksigns_iq2xs, 128) + 0, 129, 130, 3, 132, 5, 6, 135, 136, 9, 10, 139, 12, 141, 142, 15, + 144, 17, 18, 147, 20, 149, 150, 23, 24, 153, 154, 27, 156, 29, 30, 159, + 160, 33, 34, 163, 36, 165, 166, 39, 40, 169, 170, 43, 172, 45, 46, 175, + 48, 177, 178, 51, 180, 53, 54, 183, 184, 57, 58, 187, 60, 189, 190, 63, + 192, 65, 66, 195, 68, 197, 198, 71, 72, 201, 202, 75, 204, 77, 78, 207, + 80, 209, 210, 83, 212, 85, 86, 215, 216, 89, 90, 219, 92, 221, 222, 95, + 96, 225, 226, 99, 228, 101, 102, 231, 232, 105, 106, 235, 108, 237, 238, 111, + 240, 113, 114, 243, 116, 245, 246, 119, 120, 249, 250, 123, 252, 125, 126, 255, +GGML_TABLE_END() + +//#if __CUDA_ARCH__ >= MIN_CC_DP4A // lowest compute capability for integer intrinsics +GGML_TABLE_BEGIN(uint64_t, ksigns64, 128) + 0x0000000000000000, 0xff000000000000ff, 0xff0000000000ff00, 0x000000000000ffff, + 0xff00000000ff0000, 0x0000000000ff00ff, 0x0000000000ffff00, 0xff00000000ffffff, + 0xff000000ff000000, 0x00000000ff0000ff, 0x00000000ff00ff00, 0xff000000ff00ffff, + 0x00000000ffff0000, 0xff000000ffff00ff, 0xff000000ffffff00, 0x00000000ffffffff, + 0xff0000ff00000000, 0x000000ff000000ff, 0x000000ff0000ff00, 0xff0000ff0000ffff, + 0x000000ff00ff0000, 0xff0000ff00ff00ff, 0xff0000ff00ffff00, 0x000000ff00ffffff, + 0x000000ffff000000, 0xff0000ffff0000ff, 0xff0000ffff00ff00, 0x000000ffff00ffff, + 0xff0000ffffff0000, 0x000000ffffff00ff, 0x000000ffffffff00, 0xff0000ffffffffff, + 0xff00ff0000000000, 0x0000ff00000000ff, 0x0000ff000000ff00, 0xff00ff000000ffff, + 0x0000ff0000ff0000, 0xff00ff0000ff00ff, 0xff00ff0000ffff00, 0x0000ff0000ffffff, + 0x0000ff00ff000000, 0xff00ff00ff0000ff, 0xff00ff00ff00ff00, 0x0000ff00ff00ffff, + 0xff00ff00ffff0000, 0x0000ff00ffff00ff, 0x0000ff00ffffff00, 0xff00ff00ffffffff, + 0x0000ffff00000000, 0xff00ffff000000ff, 0xff00ffff0000ff00, 0x0000ffff0000ffff, + 0xff00ffff00ff0000, 0x0000ffff00ff00ff, 0x0000ffff00ffff00, 0xff00ffff00ffffff, + 0xff00ffffff000000, 0x0000ffffff0000ff, 0x0000ffffff00ff00, 0xff00ffffff00ffff, + 0x0000ffffffff0000, 0xff00ffffffff00ff, 0xff00ffffffffff00, 0x0000ffffffffffff, + 0xffff000000000000, 0x00ff0000000000ff, 0x00ff00000000ff00, 0xffff00000000ffff, + 0x00ff000000ff0000, 0xffff000000ff00ff, 0xffff000000ffff00, 0x00ff000000ffffff, + 0x00ff0000ff000000, 0xffff0000ff0000ff, 0xffff0000ff00ff00, 0x00ff0000ff00ffff, + 0xffff0000ffff0000, 0x00ff0000ffff00ff, 0x00ff0000ffffff00, 0xffff0000ffffffff, + 0x00ff00ff00000000, 0xffff00ff000000ff, 0xffff00ff0000ff00, 0x00ff00ff0000ffff, + 0xffff00ff00ff0000, 0x00ff00ff00ff00ff, 0x00ff00ff00ffff00, 0xffff00ff00ffffff, + 0xffff00ffff000000, 0x00ff00ffff0000ff, 0x00ff00ffff00ff00, 0xffff00ffff00ffff, + 0x00ff00ffffff0000, 0xffff00ffffff00ff, 0xffff00ffffffff00, 0x00ff00ffffffffff, + 0x00ffff0000000000, 0xffffff00000000ff, 0xffffff000000ff00, 0x00ffff000000ffff, + 0xffffff0000ff0000, 0x00ffff0000ff00ff, 0x00ffff0000ffff00, 0xffffff0000ffffff, + 0xffffff00ff000000, 0x00ffff00ff0000ff, 0x00ffff00ff00ff00, 0xffffff00ff00ffff, + 0x00ffff00ffff0000, 0xffffff00ffff00ff, 0xffffff00ffffff00, 0x00ffff00ffffffff, + 0xffffffff00000000, 0x00ffffff000000ff, 0x00ffffff0000ff00, 0xffffffff0000ffff, + 0x00ffffff00ff0000, 0xffffffff00ff00ff, 0xffffffff00ffff00, 0x00ffffff00ffffff, + 0x00ffffffff000000, 0xffffffffff0000ff, 0xffffffffff00ff00, 0x00ffffffff00ffff, + 0xffffffffffff0000, 0x00ffffffffff00ff, 0x00ffffffffffff00, 0xffffffffffffffff, +GGML_TABLE_END() +//#endif + + +GGML_TABLE_BEGIN(uint64_t, iq2xxs_grid, 256) + 0x0808080808080808, 0x080808080808082b, 0x0808080808081919, 0x0808080808082b08, + 0x0808080808082b2b, 0x0808080808190819, 0x0808080808191908, 0x08080808082b0808, + 0x08080808082b082b, 0x08080808082b2b08, 0x08080808082b2b2b, 0x0808080819080819, + 0x0808080819081908, 0x0808080819190808, 0x0808080819192b08, 0x08080808192b0819, + 0x08080808192b1908, 0x080808082b080808, 0x080808082b08082b, 0x080808082b082b2b, + 0x080808082b2b082b, 0x0808081908080819, 0x0808081908081908, 0x0808081908190808, + 0x0808081908191919, 0x0808081919080808, 0x080808192b081908, 0x080808192b192b08, + 0x0808082b08080808, 0x0808082b0808082b, 0x0808082b082b082b, 0x0808082b2b08082b, + 0x0808190808080819, 0x0808190808081908, 0x0808190808190808, 0x08081908082b0819, + 0x08081908082b1908, 0x0808190819080808, 0x080819081908082b, 0x0808190819082b08, + 0x08081908192b0808, 0x080819082b080819, 0x080819082b081908, 0x080819082b190808, + 0x080819082b2b1908, 0x0808191908080808, 0x080819190808082b, 0x0808191908082b08, + 0x08081919082b0808, 0x080819191908192b, 0x08081919192b2b19, 0x080819192b080808, + 0x080819192b190819, 0x0808192b08082b19, 0x0808192b08190808, 0x0808192b19080808, + 0x0808192b2b081908, 0x0808192b2b2b1908, 0x08082b0808080808, 0x08082b0808081919, + 0x08082b0808082b08, 0x08082b0808191908, 0x08082b08082b2b08, 0x08082b0819080819, + 0x08082b0819081908, 0x08082b0819190808, 0x08082b081919082b, 0x08082b082b082b08, + 0x08082b1908081908, 0x08082b1919080808, 0x08082b2b0808082b, 0x08082b2b08191908, + 0x0819080808080819, 0x0819080808081908, 0x0819080808190808, 0x08190808082b0819, + 0x0819080819080808, 0x08190808192b0808, 0x081908082b081908, 0x081908082b190808, + 0x081908082b191919, 0x0819081908080808, 0x0819081908082b08, 0x08190819082b0808, + 0x0819081919190808, 0x0819081919192b2b, 0x081908192b080808, 0x0819082b082b1908, + 0x0819082b19081919, 0x0819190808080808, 0x0819190808082b08, 0x08191908082b0808, + 0x08191908082b1919, 0x0819190819082b19, 0x081919082b080808, 0x0819191908192b08, + 0x08191919192b082b, 0x0819192b08080808, 0x0819192b0819192b, 0x08192b0808080819, + 0x08192b0808081908, 0x08192b0808190808, 0x08192b0819080808, 0x08192b082b080819, + 0x08192b1908080808, 0x08192b1908081919, 0x08192b192b2b0808, 0x08192b2b19190819, + 0x082b080808080808, 0x082b08080808082b, 0x082b080808082b2b, 0x082b080819081908, + 0x082b0808192b0819, 0x082b08082b080808, 0x082b08082b08082b, 0x082b0819082b2b19, + 0x082b081919082b08, 0x082b082b08080808, 0x082b082b0808082b, 0x082b190808080819, + 0x082b190808081908, 0x082b190808190808, 0x082b190819080808, 0x082b19081919192b, + 0x082b191908080808, 0x082b191919080819, 0x082b1919192b1908, 0x082b192b2b190808, + 0x082b2b0808082b08, 0x082b2b08082b0808, 0x082b2b082b191908, 0x082b2b2b19081908, + 0x1908080808080819, 0x1908080808081908, 0x1908080808190808, 0x1908080808192b08, + 0x19080808082b0819, 0x19080808082b1908, 0x1908080819080808, 0x1908080819082b08, + 0x190808081919192b, 0x19080808192b0808, 0x190808082b080819, 0x190808082b081908, + 0x190808082b190808, 0x1908081908080808, 0x19080819082b0808, 0x19080819192b0819, + 0x190808192b080808, 0x190808192b081919, 0x1908082b08080819, 0x1908082b08190808, + 0x1908082b19082b08, 0x1908082b1919192b, 0x1908082b192b2b08, 0x1908190808080808, + 0x1908190808082b08, 0x19081908082b0808, 0x190819082b080808, 0x190819082b192b19, + 0x190819190819082b, 0x19081919082b1908, 0x1908192b08080808, 0x19082b0808080819, + 0x19082b0808081908, 0x19082b0808190808, 0x19082b0819080808, 0x19082b0819081919, + 0x19082b1908080808, 0x19082b1919192b08, 0x19082b19192b0819, 0x19082b192b08082b, + 0x19082b2b19081919, 0x19082b2b2b190808, 0x1919080808080808, 0x1919080808082b08, + 0x1919080808190819, 0x1919080808192b19, 0x19190808082b0808, 0x191908082b080808, + 0x191908082b082b08, 0x1919081908081908, 0x191908191908082b, 0x191908192b2b1908, + 0x1919082b2b190819, 0x191919082b190808, 0x191919082b19082b, 0x1919191908082b2b, + 0x1919192b08080819, 0x1919192b19191908, 0x19192b0808080808, 0x19192b0808190819, + 0x19192b0808192b19, 0x19192b08192b1908, 0x19192b1919080808, 0x19192b2b08082b08, + 0x192b080808081908, 0x192b080808190808, 0x192b080819080808, 0x192b0808192b2b08, + 0x192b081908080808, 0x192b081919191919, 0x192b082b08192b08, 0x192b082b192b0808, + 0x192b190808080808, 0x192b190808081919, 0x192b191908190808, 0x192b19190819082b, + 0x192b19192b081908, 0x192b2b081908082b, 0x2b08080808080808, 0x2b0808080808082b, + 0x2b08080808082b2b, 0x2b08080819080819, 0x2b0808082b08082b, 0x2b08081908081908, + 0x2b08081908192b08, 0x2b08081919080808, 0x2b08082b08190819, 0x2b08190808080819, + 0x2b08190808081908, 0x2b08190808190808, 0x2b08190808191919, 0x2b08190819080808, + 0x2b081908192b0808, 0x2b08191908080808, 0x2b0819191908192b, 0x2b0819192b191908, + 0x2b08192b08082b19, 0x2b08192b19080808, 0x2b08192b192b0808, 0x2b082b080808082b, + 0x2b082b1908081908, 0x2b082b2b08190819, 0x2b19080808081908, 0x2b19080808190808, + 0x2b190808082b1908, 0x2b19080819080808, 0x2b1908082b2b0819, 0x2b1908190819192b, + 0x2b1908192b080808, 0x2b19082b19081919, 0x2b19190808080808, 0x2b191908082b082b, + 0x2b19190819081908, 0x2b19191919190819, 0x2b192b082b080819, 0x2b192b19082b0808, + 0x2b2b08080808082b, 0x2b2b080819190808, 0x2b2b08082b081919, 0x2b2b081908082b19, + 0x2b2b082b08080808, 0x2b2b190808192b08, 0x2b2b2b0819190808, 0x2b2b2b1908081908, +GGML_TABLE_END() + +GGML_TABLE_BEGIN(uint64_t, iq2xs_grid, 512) + 0x0808080808080808, 0x080808080808082b, 0x0808080808081919, 0x0808080808082b08, + 0x0808080808082b2b, 0x0808080808190819, 0x0808080808191908, 0x080808080819192b, + 0x0808080808192b19, 0x08080808082b0808, 0x08080808082b082b, 0x08080808082b1919, + 0x08080808082b2b08, 0x0808080819080819, 0x0808080819081908, 0x080808081908192b, + 0x0808080819082b19, 0x0808080819190808, 0x080808081919082b, 0x0808080819191919, + 0x0808080819192b08, 0x08080808192b0819, 0x08080808192b1908, 0x080808082b080808, + 0x080808082b08082b, 0x080808082b081919, 0x080808082b082b08, 0x080808082b190819, + 0x080808082b191908, 0x080808082b192b19, 0x080808082b2b0808, 0x0808081908080819, + 0x0808081908081908, 0x080808190808192b, 0x0808081908082b19, 0x0808081908190808, + 0x080808190819082b, 0x0808081908191919, 0x0808081908192b08, 0x0808081908192b2b, + 0x08080819082b0819, 0x08080819082b1908, 0x0808081919080808, 0x080808191908082b, + 0x0808081919081919, 0x0808081919082b08, 0x0808081919190819, 0x0808081919191908, + 0x08080819192b0808, 0x08080819192b2b08, 0x080808192b080819, 0x080808192b081908, + 0x080808192b190808, 0x0808082b08080808, 0x0808082b0808082b, 0x0808082b08081919, + 0x0808082b08082b08, 0x0808082b08190819, 0x0808082b08191908, 0x0808082b082b0808, + 0x0808082b19080819, 0x0808082b19081908, 0x0808082b19190808, 0x0808082b19191919, + 0x0808082b2b080808, 0x0808082b2b082b2b, 0x0808190808080819, 0x0808190808081908, + 0x080819080808192b, 0x0808190808082b19, 0x0808190808190808, 0x080819080819082b, + 0x0808190808191919, 0x0808190808192b08, 0x08081908082b0819, 0x08081908082b1908, + 0x0808190819080808, 0x080819081908082b, 0x0808190819081919, 0x0808190819082b08, + 0x0808190819190819, 0x0808190819191908, 0x080819081919192b, 0x08081908192b0808, + 0x080819082b080819, 0x080819082b081908, 0x080819082b190808, 0x0808191908080808, + 0x080819190808082b, 0x0808191908081919, 0x0808191908082b08, 0x0808191908190819, + 0x0808191908191908, 0x08081919082b0808, 0x0808191919080819, 0x0808191919081908, + 0x0808191919190808, 0x08081919192b0819, 0x080819192b080808, 0x0808192b08080819, + 0x0808192b08081908, 0x0808192b08190808, 0x0808192b082b192b, 0x0808192b19080808, + 0x0808192b1908082b, 0x0808192b2b081908, 0x08082b0808080808, 0x08082b080808082b, + 0x08082b0808081919, 0x08082b0808082b08, 0x08082b0808082b2b, 0x08082b0808190819, + 0x08082b0808191908, 0x08082b08082b0808, 0x08082b08082b1919, 0x08082b0819080819, + 0x08082b0819081908, 0x08082b0819190808, 0x08082b0819192b08, 0x08082b082b080808, + 0x08082b082b2b0808, 0x08082b082b2b2b2b, 0x08082b1908080819, 0x08082b1908081908, + 0x08082b1908190808, 0x08082b1919080808, 0x08082b192b080819, 0x08082b192b082b19, + 0x08082b2b08080808, 0x08082b2b082b0808, 0x08082b2b082b2b08, 0x08082b2b2b19192b, + 0x08082b2b2b2b0808, 0x0819080808080819, 0x0819080808081908, 0x081908080808192b, + 0x0819080808082b19, 0x0819080808190808, 0x081908080819082b, 0x0819080808191919, + 0x0819080808192b08, 0x08190808082b0819, 0x08190808082b1908, 0x0819080819080808, + 0x081908081908082b, 0x0819080819081919, 0x0819080819082b08, 0x0819080819190819, + 0x0819080819191908, 0x08190808192b0808, 0x08190808192b2b2b, 0x081908082b080819, + 0x081908082b081908, 0x081908082b190808, 0x0819081908080808, 0x081908190808082b, + 0x0819081908081919, 0x0819081908082b08, 0x0819081908190819, 0x0819081908191908, + 0x08190819082b0808, 0x0819081919080819, 0x0819081919081908, 0x0819081919190808, + 0x081908192b080808, 0x081908192b191908, 0x081908192b19192b, 0x0819082b08080819, + 0x0819082b08081908, 0x0819082b0808192b, 0x0819082b08190808, 0x0819082b19080808, + 0x0819082b192b0808, 0x0819190808080808, 0x081919080808082b, 0x0819190808081919, + 0x0819190808082b08, 0x0819190808190819, 0x0819190808191908, 0x08191908082b0808, + 0x0819190819080819, 0x0819190819081908, 0x0819190819082b19, 0x0819190819190808, + 0x08191908192b1908, 0x081919082b080808, 0x0819191908080819, 0x0819191908081908, + 0x0819191908190808, 0x0819191919080808, 0x0819192b08080808, 0x0819192b08191908, + 0x0819192b19082b19, 0x08192b0808080819, 0x08192b0808081908, 0x08192b0808190808, + 0x08192b080819082b, 0x08192b0819080808, 0x08192b0819191908, 0x08192b082b08192b, + 0x08192b1908080808, 0x08192b1908081919, 0x08192b19192b192b, 0x08192b2b19190819, + 0x08192b2b2b2b2b19, 0x082b080808080808, 0x082b08080808082b, 0x082b080808081919, + 0x082b080808082b08, 0x082b080808082b2b, 0x082b080808190819, 0x082b080808191908, + 0x082b0808082b0808, 0x082b080819080819, 0x082b080819081908, 0x082b080819190808, + 0x082b08082b080808, 0x082b08082b2b0808, 0x082b081908080819, 0x082b081908081908, + 0x082b081908190808, 0x082b081919080808, 0x082b081919082b08, 0x082b0819192b1919, + 0x082b082b08080808, 0x082b082b082b082b, 0x082b082b2b080808, 0x082b082b2b2b2b08, + 0x082b190808080819, 0x082b190808081908, 0x082b190808190808, 0x082b1908082b2b19, + 0x082b190819080808, 0x082b191908080808, 0x082b191919080819, 0x082b19191919082b, + 0x082b19192b192b19, 0x082b192b08080819, 0x082b192b08192b2b, 0x082b192b2b2b192b, + 0x082b2b0808080808, 0x082b2b0808082b08, 0x082b2b0808082b2b, 0x082b2b08082b0808, + 0x082b2b0819191919, 0x082b2b082b082b08, 0x082b2b082b2b082b, 0x082b2b19192b2b08, + 0x082b2b192b190808, 0x082b2b2b08082b08, 0x082b2b2b082b0808, 0x082b2b2b2b08082b, + 0x082b2b2b2b082b08, 0x082b2b2b2b082b2b, 0x1908080808080819, 0x1908080808081908, + 0x190808080808192b, 0x1908080808082b19, 0x1908080808190808, 0x190808080819082b, + 0x1908080808191919, 0x1908080808192b08, 0x19080808082b0819, 0x19080808082b1908, + 0x1908080819080808, 0x190808081908082b, 0x1908080819081919, 0x1908080819082b08, + 0x1908080819082b2b, 0x1908080819190819, 0x1908080819191908, 0x19080808192b0808, + 0x19080808192b1919, 0x190808082b080819, 0x190808082b081908, 0x190808082b190808, + 0x1908081908080808, 0x190808190808082b, 0x1908081908081919, 0x1908081908082b08, + 0x1908081908190819, 0x1908081908191908, 0x19080819082b0808, 0x1908081919080819, + 0x1908081919081908, 0x1908081919190808, 0x190808192b080808, 0x190808192b081919, + 0x190808192b2b082b, 0x1908082b08080819, 0x1908082b08081908, 0x1908082b08190808, + 0x1908082b0819082b, 0x1908082b082b2b19, 0x1908082b19080808, 0x1908190808080808, + 0x190819080808082b, 0x1908190808081919, 0x1908190808082b08, 0x1908190808190819, + 0x1908190808191908, 0x1908190808192b19, 0x19081908082b0808, 0x1908190819080819, + 0x1908190819081908, 0x1908190819190808, 0x190819082b080808, 0x190819082b191908, + 0x1908191908080819, 0x1908191908081908, 0x1908191908190808, 0x19081919082b1908, + 0x1908191919080808, 0x190819192b192b2b, 0x1908192b08080808, 0x1908192b08082b2b, + 0x1908192b19081908, 0x1908192b19190808, 0x19082b0808080819, 0x19082b0808081908, + 0x19082b0808190808, 0x19082b0819080808, 0x19082b0819081919, 0x19082b0819191908, + 0x19082b08192b082b, 0x19082b1908080808, 0x19082b1908190819, 0x19082b1919081908, + 0x19082b1919190808, 0x19082b19192b2b19, 0x19082b2b08081908, 0x1919080808080808, + 0x191908080808082b, 0x1919080808081919, 0x1919080808082b08, 0x1919080808190819, + 0x1919080808191908, 0x19190808082b0808, 0x19190808082b2b08, 0x1919080819080819, + 0x1919080819081908, 0x1919080819190808, 0x191908082b080808, 0x1919081908080819, + 0x1919081908081908, 0x1919081908190808, 0x1919081908191919, 0x1919081919080808, + 0x191908191908082b, 0x1919082b08080808, 0x1919082b19081908, 0x1919082b2b2b2b2b, + 0x1919190808080819, 0x1919190808081908, 0x1919190808190808, 0x19191908082b0819, + 0x1919190819080808, 0x19191908192b0808, 0x191919082b080819, 0x191919082b2b0819, + 0x1919191908080808, 0x1919191908082b08, 0x191919192b080808, 0x191919192b082b08, + 0x1919192b082b0819, 0x1919192b192b2b08, 0x1919192b2b2b0819, 0x19192b0808080808, + 0x19192b0808191908, 0x19192b0819080819, 0x19192b0819190808, 0x19192b082b192b19, + 0x19192b1908192b2b, 0x19192b1919080808, 0x19192b191908082b, 0x19192b2b2b081919, + 0x192b080808080819, 0x192b080808081908, 0x192b080808190808, 0x192b080819080808, + 0x192b080819191908, 0x192b0808192b082b, 0x192b08082b08192b, 0x192b08082b2b2b19, + 0x192b081908080808, 0x192b082b082b1908, 0x192b082b19082b2b, 0x192b082b2b19082b, + 0x192b190808080808, 0x192b19080819192b, 0x192b191908190808, 0x192b191919080808, + 0x192b191919081919, 0x192b19192b2b1908, 0x192b2b0808080819, 0x192b2b08192b2b2b, + 0x192b2b19082b1919, 0x192b2b2b0808192b, 0x192b2b2b19191908, 0x192b2b2b192b082b, + 0x2b08080808080808, 0x2b0808080808082b, 0x2b08080808081919, 0x2b08080808082b08, + 0x2b08080808190819, 0x2b08080808191908, 0x2b080808082b0808, 0x2b080808082b2b2b, + 0x2b08080819080819, 0x2b08080819081908, 0x2b08080819190808, 0x2b0808082b080808, + 0x2b0808082b08082b, 0x2b0808082b2b2b08, 0x2b0808082b2b2b2b, 0x2b08081908080819, + 0x2b08081908081908, 0x2b0808190808192b, 0x2b08081908190808, 0x2b08081919080808, + 0x2b08081919190819, 0x2b08081919192b19, 0x2b08082b08080808, 0x2b08082b082b0808, + 0x2b08082b2b080808, 0x2b08082b2b08082b, 0x2b08082b2b2b0808, 0x2b08082b2b2b2b08, + 0x2b08190808080819, 0x2b08190808081908, 0x2b08190808190808, 0x2b0819080819082b, + 0x2b08190808191919, 0x2b08190819080808, 0x2b081908192b0808, 0x2b0819082b082b19, + 0x2b08191908080808, 0x2b08191919081908, 0x2b0819192b2b1919, 0x2b08192b08192b08, + 0x2b08192b192b2b2b, 0x2b082b0808080808, 0x2b082b0808082b08, 0x2b082b08082b1919, + 0x2b082b0819192b2b, 0x2b082b082b080808, 0x2b082b082b08082b, 0x2b082b082b2b2b08, + 0x2b082b190808192b, 0x2b082b2b082b082b, 0x2b082b2b2b080808, 0x2b082b2b2b082b08, + 0x2b082b2b2b19192b, 0x2b082b2b2b2b2b08, 0x2b19080808080819, 0x2b19080808081908, + 0x2b19080808190808, 0x2b19080819080808, 0x2b1908081919192b, 0x2b1908082b081908, + 0x2b19081908080808, 0x2b190819082b082b, 0x2b190819192b1908, 0x2b19082b1919192b, + 0x2b19082b2b082b19, 0x2b19190808080808, 0x2b19190808081919, 0x2b19190819081908, + 0x2b19190819190808, 0x2b19190819192b08, 0x2b191919082b2b19, 0x2b1919192b190808, + 0x2b1919192b19082b, 0x2b19192b19080819, 0x2b192b0819190819, 0x2b192b082b2b192b, + 0x2b192b1919082b19, 0x2b192b2b08191919, 0x2b192b2b192b0808, 0x2b2b080808080808, + 0x2b2b08080808082b, 0x2b2b080808082b08, 0x2b2b080808082b2b, 0x2b2b0808082b0808, + 0x2b2b0808082b2b2b, 0x2b2b08082b2b0808, 0x2b2b081919190819, 0x2b2b081919192b19, + 0x2b2b08192b2b192b, 0x2b2b082b08080808, 0x2b2b082b0808082b, 0x2b2b082b08082b08, + 0x2b2b082b082b2b2b, 0x2b2b082b2b080808, 0x2b2b082b2b2b0808, 0x2b2b190819080808, + 0x2b2b19082b191919, 0x2b2b192b192b1919, 0x2b2b192b2b192b08, 0x2b2b2b0808082b2b, + 0x2b2b2b08082b0808, 0x2b2b2b08082b082b, 0x2b2b2b08082b2b08, 0x2b2b2b082b2b0808, + 0x2b2b2b082b2b2b08, 0x2b2b2b1908081908, 0x2b2b2b192b081908, 0x2b2b2b192b08192b, + 0x2b2b2b2b082b2b08, 0x2b2b2b2b082b2b2b, 0x2b2b2b2b2b190819, 0x2b2b2b2b2b2b2b2b, +GGML_TABLE_END() + +GGML_TABLE_BEGIN(uint64_t, iq2s_grid, 1024) + 0x0808080808080808, 0x080808080808082b, 0x0808080808081919, 0x0808080808082b08, + 0x0808080808082b2b, 0x0808080808190819, 0x0808080808191908, 0x080808080819192b, + 0x0808080808192b19, 0x08080808082b0808, 0x08080808082b082b, 0x08080808082b1919, + 0x08080808082b2b08, 0x0808080819080819, 0x0808080819081908, 0x080808081908192b, + 0x0808080819082b19, 0x0808080819190808, 0x080808081919082b, 0x0808080819191919, + 0x0808080819192b08, 0x08080808192b0819, 0x08080808192b1908, 0x08080808192b192b, + 0x08080808192b2b19, 0x080808082b080808, 0x080808082b08082b, 0x080808082b081919, + 0x080808082b082b08, 0x080808082b190819, 0x080808082b191908, 0x080808082b2b0808, + 0x080808082b2b1919, 0x080808082b2b2b2b, 0x0808081908080819, 0x0808081908081908, + 0x080808190808192b, 0x0808081908082b19, 0x0808081908190808, 0x080808190819082b, + 0x0808081908191919, 0x0808081908192b08, 0x08080819082b0819, 0x08080819082b1908, + 0x0808081919080808, 0x080808191908082b, 0x0808081919081919, 0x0808081919082b08, + 0x0808081919190819, 0x0808081919191908, 0x080808191919192b, 0x0808081919192b19, + 0x08080819192b0808, 0x08080819192b1919, 0x08080819192b2b08, 0x080808192b080819, + 0x080808192b081908, 0x080808192b190808, 0x080808192b19082b, 0x080808192b191919, + 0x080808192b2b0819, 0x080808192b2b1908, 0x0808082b08080808, 0x0808082b0808082b, + 0x0808082b08081919, 0x0808082b08082b08, 0x0808082b08190819, 0x0808082b08191908, + 0x0808082b082b0808, 0x0808082b082b2b2b, 0x0808082b19080819, 0x0808082b19081908, + 0x0808082b1908192b, 0x0808082b19082b19, 0x0808082b19190808, 0x0808082b19191919, + 0x0808082b2b080808, 0x0808082b2b081919, 0x0808082b2b082b2b, 0x0808082b2b191908, + 0x0808082b2b2b082b, 0x0808190808080819, 0x0808190808081908, 0x080819080808192b, + 0x0808190808082b19, 0x0808190808190808, 0x080819080819082b, 0x0808190808191919, + 0x0808190808192b08, 0x08081908082b0819, 0x08081908082b1908, 0x08081908082b192b, + 0x08081908082b2b19, 0x0808190819080808, 0x080819081908082b, 0x0808190819081919, + 0x0808190819082b08, 0x0808190819082b2b, 0x0808190819190819, 0x0808190819191908, + 0x080819081919192b, 0x0808190819192b19, 0x08081908192b0808, 0x08081908192b082b, + 0x08081908192b1919, 0x080819082b080819, 0x080819082b081908, 0x080819082b08192b, + 0x080819082b082b19, 0x080819082b190808, 0x080819082b191919, 0x080819082b192b08, + 0x080819082b2b0819, 0x080819082b2b1908, 0x0808191908080808, 0x080819190808082b, + 0x0808191908081919, 0x0808191908082b08, 0x0808191908082b2b, 0x0808191908190819, + 0x0808191908191908, 0x080819190819192b, 0x0808191908192b19, 0x08081919082b0808, + 0x08081919082b1919, 0x08081919082b2b08, 0x0808191919080819, 0x0808191919081908, + 0x080819191908192b, 0x0808191919082b19, 0x0808191919190808, 0x080819191919082b, + 0x0808191919191919, 0x0808191919192b08, 0x08081919192b0819, 0x08081919192b1908, + 0x080819192b080808, 0x080819192b08082b, 0x080819192b081919, 0x080819192b082b08, + 0x080819192b190819, 0x080819192b191908, 0x080819192b2b0808, 0x0808192b08080819, + 0x0808192b08081908, 0x0808192b0808192b, 0x0808192b08082b19, 0x0808192b08190808, + 0x0808192b08191919, 0x0808192b19080808, 0x0808192b19081919, 0x0808192b19082b08, + 0x0808192b19190819, 0x0808192b19191908, 0x0808192b192b0808, 0x0808192b2b080819, + 0x0808192b2b081908, 0x0808192b2b190808, 0x08082b0808080808, 0x08082b080808082b, + 0x08082b0808081919, 0x08082b0808082b08, 0x08082b0808190819, 0x08082b0808191908, + 0x08082b080819192b, 0x08082b0808192b19, 0x08082b08082b0808, 0x08082b08082b1919, + 0x08082b08082b2b2b, 0x08082b0819080819, 0x08082b0819081908, 0x08082b081908192b, + 0x08082b0819082b19, 0x08082b0819190808, 0x08082b081919082b, 0x08082b0819191919, + 0x08082b0819192b08, 0x08082b08192b0819, 0x08082b08192b1908, 0x08082b082b080808, + 0x08082b082b081919, 0x08082b082b191908, 0x08082b082b2b2b2b, 0x08082b1908080819, + 0x08082b1908081908, 0x08082b1908190808, 0x08082b190819082b, 0x08082b1908191919, + 0x08082b1908192b08, 0x08082b19082b0819, 0x08082b1919080808, 0x08082b1919081919, + 0x08082b1919082b08, 0x08082b1919190819, 0x08082b1919191908, 0x08082b19192b0808, + 0x08082b192b080819, 0x08082b192b190808, 0x08082b2b08080808, 0x08082b2b08190819, + 0x08082b2b08191908, 0x08082b2b082b082b, 0x08082b2b082b2b08, 0x08082b2b082b2b2b, + 0x08082b2b19190808, 0x08082b2b2b192b19, 0x0819080808080819, 0x0819080808081908, + 0x081908080808192b, 0x0819080808082b19, 0x0819080808190808, 0x081908080819082b, + 0x0819080808191919, 0x0819080808192b08, 0x08190808082b0819, 0x08190808082b1908, + 0x08190808082b192b, 0x0819080819080808, 0x081908081908082b, 0x0819080819081919, + 0x0819080819082b08, 0x0819080819190819, 0x0819080819191908, 0x081908081919192b, + 0x0819080819192b19, 0x08190808192b0808, 0x08190808192b082b, 0x08190808192b1919, + 0x08190808192b2b08, 0x081908082b080819, 0x081908082b081908, 0x081908082b08192b, + 0x081908082b190808, 0x081908082b191919, 0x081908082b192b08, 0x081908082b2b0819, + 0x081908082b2b1908, 0x0819081908080808, 0x081908190808082b, 0x0819081908081919, + 0x0819081908082b08, 0x0819081908082b2b, 0x0819081908190819, 0x0819081908191908, + 0x081908190819192b, 0x0819081908192b19, 0x08190819082b0808, 0x08190819082b082b, + 0x08190819082b1919, 0x08190819082b2b08, 0x0819081919080819, 0x0819081919081908, + 0x081908191908192b, 0x0819081919082b19, 0x0819081919190808, 0x081908191919082b, + 0x0819081919191919, 0x0819081919192b08, 0x08190819192b0819, 0x08190819192b1908, + 0x081908192b080808, 0x081908192b08082b, 0x081908192b081919, 0x081908192b082b08, + 0x081908192b190819, 0x081908192b191908, 0x0819082b08080819, 0x0819082b08081908, + 0x0819082b08082b19, 0x0819082b08190808, 0x0819082b08191919, 0x0819082b082b0819, + 0x0819082b082b1908, 0x0819082b19080808, 0x0819082b19081919, 0x0819082b19190819, + 0x0819082b19191908, 0x0819082b2b080819, 0x0819082b2b081908, 0x0819082b2b190808, + 0x0819190808080808, 0x081919080808082b, 0x0819190808081919, 0x0819190808082b08, + 0x0819190808190819, 0x0819190808191908, 0x081919080819192b, 0x0819190808192b19, + 0x08191908082b0808, 0x08191908082b1919, 0x08191908082b2b08, 0x0819190819080819, + 0x0819190819081908, 0x081919081908192b, 0x0819190819082b19, 0x0819190819190808, + 0x081919081919082b, 0x0819190819191919, 0x0819190819192b08, 0x08191908192b0819, + 0x08191908192b1908, 0x081919082b080808, 0x081919082b08082b, 0x081919082b081919, + 0x081919082b082b08, 0x081919082b190819, 0x081919082b191908, 0x081919082b2b0808, + 0x0819191908080819, 0x0819191908081908, 0x081919190808192b, 0x0819191908082b19, + 0x0819191908190808, 0x081919190819082b, 0x0819191908191919, 0x0819191908192b08, + 0x08191919082b0819, 0x08191919082b1908, 0x0819191919080808, 0x081919191908082b, + 0x0819191919081919, 0x0819191919082b08, 0x0819191919190819, 0x0819191919191908, + 0x08191919192b0808, 0x081919192b080819, 0x081919192b081908, 0x081919192b190808, + 0x0819192b08080808, 0x0819192b08081919, 0x0819192b08082b08, 0x0819192b08190819, + 0x0819192b08191908, 0x0819192b082b0808, 0x0819192b19080819, 0x0819192b19081908, + 0x0819192b19190808, 0x0819192b2b080808, 0x0819192b2b2b2b2b, 0x08192b0808080819, + 0x08192b0808081908, 0x08192b080808192b, 0x08192b0808082b19, 0x08192b0808190808, + 0x08192b0808191919, 0x08192b0808192b08, 0x08192b08082b0819, 0x08192b0819080808, + 0x08192b081908082b, 0x08192b0819081919, 0x08192b0819082b08, 0x08192b0819190819, + 0x08192b0819191908, 0x08192b08192b0808, 0x08192b082b080819, 0x08192b082b081908, + 0x08192b1908080808, 0x08192b190808082b, 0x08192b1908081919, 0x08192b1908082b08, + 0x08192b1908190819, 0x08192b1908191908, 0x08192b19082b0808, 0x08192b1919080819, + 0x08192b1919081908, 0x08192b1919190808, 0x08192b19192b2b19, 0x08192b192b2b082b, + 0x08192b2b08081908, 0x08192b2b08190808, 0x08192b2b19080808, 0x08192b2b1919192b, + 0x082b080808080808, 0x082b08080808082b, 0x082b080808081919, 0x082b080808082b08, + 0x082b080808190819, 0x082b080808191908, 0x082b08080819192b, 0x082b080808192b19, + 0x082b0808082b0808, 0x082b0808082b1919, 0x082b0808082b2b2b, 0x082b080819080819, + 0x082b080819081908, 0x082b080819190808, 0x082b08081919082b, 0x082b080819191919, + 0x082b0808192b1908, 0x082b08082b080808, 0x082b08082b082b2b, 0x082b08082b191908, + 0x082b08082b2b2b2b, 0x082b081908080819, 0x082b081908081908, 0x082b081908190808, + 0x082b08190819082b, 0x082b081908191919, 0x082b0819082b0819, 0x082b081919080808, + 0x082b08191908082b, 0x082b081919081919, 0x082b081919190819, 0x082b081919191908, + 0x082b0819192b0808, 0x082b08192b080819, 0x082b08192b081908, 0x082b08192b190808, + 0x082b082b08080808, 0x082b082b08082b2b, 0x082b082b082b082b, 0x082b082b082b2b08, + 0x082b082b082b2b2b, 0x082b082b19081908, 0x082b082b19190808, 0x082b082b2b082b08, + 0x082b082b2b082b2b, 0x082b082b2b2b2b08, 0x082b190808080819, 0x082b190808081908, + 0x082b19080808192b, 0x082b190808082b19, 0x082b190808190808, 0x082b190808191919, + 0x082b190808192b08, 0x082b1908082b0819, 0x082b1908082b1908, 0x082b190819080808, + 0x082b19081908082b, 0x082b190819081919, 0x082b190819082b08, 0x082b190819190819, + 0x082b190819191908, 0x082b1908192b0808, 0x082b19082b080819, 0x082b19082b081908, + 0x082b19082b190808, 0x082b191908080808, 0x082b191908081919, 0x082b191908082b08, + 0x082b191908190819, 0x082b191908191908, 0x082b1919082b0808, 0x082b191919080819, + 0x082b191919081908, 0x082b191919190808, 0x082b1919192b192b, 0x082b19192b080808, + 0x082b192b08080819, 0x082b192b08081908, 0x082b192b08190808, 0x082b192b19080808, + 0x082b192b19192b19, 0x082b2b0808080808, 0x082b2b0808081919, 0x082b2b0808190819, + 0x082b2b0808191908, 0x082b2b0819080819, 0x082b2b0819081908, 0x082b2b0819190808, + 0x082b2b082b082b2b, 0x082b2b082b2b2b2b, 0x082b2b1908080819, 0x082b2b1908081908, + 0x082b2b1908190808, 0x082b2b192b191919, 0x082b2b2b08082b2b, 0x082b2b2b082b082b, + 0x082b2b2b192b1908, 0x082b2b2b2b082b08, 0x082b2b2b2b082b2b, 0x1908080808080819, + 0x1908080808081908, 0x190808080808192b, 0x1908080808082b19, 0x1908080808190808, + 0x190808080819082b, 0x1908080808191919, 0x1908080808192b08, 0x1908080808192b2b, + 0x19080808082b0819, 0x19080808082b1908, 0x19080808082b192b, 0x1908080819080808, + 0x190808081908082b, 0x1908080819081919, 0x1908080819082b08, 0x1908080819082b2b, + 0x1908080819190819, 0x1908080819191908, 0x190808081919192b, 0x1908080819192b19, + 0x19080808192b0808, 0x19080808192b082b, 0x19080808192b1919, 0x190808082b080819, + 0x190808082b081908, 0x190808082b190808, 0x190808082b191919, 0x190808082b192b08, + 0x190808082b2b0819, 0x190808082b2b1908, 0x1908081908080808, 0x190808190808082b, + 0x1908081908081919, 0x1908081908082b08, 0x1908081908190819, 0x1908081908191908, + 0x190808190819192b, 0x1908081908192b19, 0x19080819082b0808, 0x19080819082b082b, + 0x19080819082b1919, 0x1908081919080819, 0x1908081919081908, 0x190808191908192b, + 0x1908081919082b19, 0x1908081919190808, 0x190808191919082b, 0x1908081919191919, + 0x1908081919192b08, 0x19080819192b0819, 0x19080819192b1908, 0x190808192b080808, + 0x190808192b08082b, 0x190808192b081919, 0x190808192b082b08, 0x190808192b190819, + 0x190808192b191908, 0x190808192b2b0808, 0x1908082b08080819, 0x1908082b08081908, + 0x1908082b08190808, 0x1908082b0819082b, 0x1908082b08191919, 0x1908082b08192b08, + 0x1908082b082b1908, 0x1908082b19080808, 0x1908082b19081919, 0x1908082b19082b08, + 0x1908082b19190819, 0x1908082b19191908, 0x1908082b192b0808, 0x1908082b2b080819, + 0x1908082b2b081908, 0x1908190808080808, 0x190819080808082b, 0x1908190808081919, + 0x1908190808082b08, 0x1908190808082b2b, 0x1908190808190819, 0x1908190808191908, + 0x190819080819192b, 0x1908190808192b19, 0x19081908082b0808, 0x19081908082b082b, + 0x19081908082b1919, 0x19081908082b2b08, 0x1908190819080819, 0x1908190819081908, + 0x190819081908192b, 0x1908190819082b19, 0x1908190819190808, 0x190819081919082b, + 0x1908190819191919, 0x1908190819192b08, 0x19081908192b0819, 0x19081908192b1908, + 0x190819082b080808, 0x190819082b08082b, 0x190819082b081919, 0x190819082b082b08, + 0x190819082b190819, 0x190819082b191908, 0x190819082b2b0808, 0x1908191908080819, + 0x1908191908081908, 0x190819190808192b, 0x1908191908082b19, 0x1908191908190808, + 0x190819190819082b, 0x1908191908191919, 0x1908191908192b08, 0x19081919082b0819, + 0x19081919082b1908, 0x1908191919080808, 0x190819191908082b, 0x1908191919081919, + 0x1908191919082b08, 0x1908191919190819, 0x1908191919191908, 0x19081919192b0808, + 0x19081919192b2b2b, 0x190819192b080819, 0x190819192b081908, 0x190819192b190808, + 0x1908192b08080808, 0x1908192b0808082b, 0x1908192b08081919, 0x1908192b08082b08, + 0x1908192b08190819, 0x1908192b08191908, 0x1908192b082b0808, 0x1908192b19080819, + 0x1908192b19081908, 0x1908192b19190808, 0x1908192b2b080808, 0x1908192b2b2b1919, + 0x19082b0808080819, 0x19082b0808081908, 0x19082b0808082b19, 0x19082b0808190808, + 0x19082b080819082b, 0x19082b0808191919, 0x19082b0808192b08, 0x19082b08082b0819, + 0x19082b08082b1908, 0x19082b0819080808, 0x19082b081908082b, 0x19082b0819081919, + 0x19082b0819082b08, 0x19082b0819190819, 0x19082b0819191908, 0x19082b08192b0808, + 0x19082b082b081908, 0x19082b082b190808, 0x19082b1908080808, 0x19082b190808082b, + 0x19082b1908081919, 0x19082b1908082b08, 0x19082b1908190819, 0x19082b1908191908, + 0x19082b19082b0808, 0x19082b1919080819, 0x19082b1919081908, 0x19082b1919190808, + 0x19082b192b080808, 0x19082b192b19192b, 0x19082b2b08080819, 0x19082b2b08081908, + 0x19082b2b08190808, 0x19082b2b19080808, 0x1919080808080808, 0x191908080808082b, + 0x1919080808081919, 0x1919080808082b08, 0x1919080808190819, 0x1919080808191908, + 0x191908080819192b, 0x1919080808192b19, 0x19190808082b0808, 0x19190808082b082b, + 0x19190808082b1919, 0x19190808082b2b08, 0x1919080819080819, 0x1919080819081908, + 0x191908081908192b, 0x1919080819082b19, 0x1919080819190808, 0x191908081919082b, + 0x1919080819191919, 0x1919080819192b08, 0x19190808192b0819, 0x19190808192b1908, + 0x191908082b080808, 0x191908082b08082b, 0x191908082b081919, 0x191908082b082b08, + 0x191908082b190819, 0x191908082b191908, 0x1919081908080819, 0x1919081908081908, + 0x191908190808192b, 0x1919081908082b19, 0x1919081908190808, 0x191908190819082b, + 0x1919081908191919, 0x1919081908192b08, 0x19190819082b0819, 0x19190819082b1908, + 0x1919081919080808, 0x191908191908082b, 0x1919081919081919, 0x1919081919082b08, + 0x1919081919190819, 0x1919081919191908, 0x19190819192b0808, 0x191908192b080819, + 0x191908192b081908, 0x191908192b190808, 0x1919082b08080808, 0x1919082b08081919, + 0x1919082b08082b08, 0x1919082b08190819, 0x1919082b08191908, 0x1919082b082b0808, + 0x1919082b19080819, 0x1919082b19081908, 0x1919082b19190808, 0x1919082b192b2b19, + 0x1919082b2b080808, 0x1919190808080819, 0x1919190808081908, 0x191919080808192b, + 0x1919190808082b19, 0x1919190808190808, 0x191919080819082b, 0x1919190808191919, + 0x1919190808192b08, 0x19191908082b0819, 0x19191908082b1908, 0x1919190819080808, + 0x191919081908082b, 0x1919190819081919, 0x1919190819082b08, 0x1919190819190819, + 0x1919190819191908, 0x19191908192b0808, 0x191919082b080819, 0x191919082b081908, + 0x191919082b190808, 0x1919191908080808, 0x191919190808082b, 0x1919191908081919, + 0x1919191908082b08, 0x1919191908190819, 0x1919191908191908, 0x19191919082b0808, + 0x1919191919080819, 0x1919191919081908, 0x1919191919190808, 0x191919192b080808, + 0x1919192b08080819, 0x1919192b08081908, 0x1919192b08190808, 0x1919192b082b192b, + 0x1919192b19080808, 0x19192b0808080808, 0x19192b080808082b, 0x19192b0808081919, + 0x19192b0808082b08, 0x19192b0808190819, 0x19192b0808191908, 0x19192b08082b0808, + 0x19192b0819080819, 0x19192b0819081908, 0x19192b0819190808, 0x19192b0819192b2b, + 0x19192b082b080808, 0x19192b1908080819, 0x19192b1908081908, 0x19192b1908190808, + 0x19192b1919080808, 0x19192b2b08080808, 0x19192b2b08192b19, 0x19192b2b2b081919, + 0x19192b2b2b2b2b08, 0x192b080808080819, 0x192b080808081908, 0x192b08080808192b, + 0x192b080808190808, 0x192b08080819082b, 0x192b080808191919, 0x192b080808192b08, + 0x192b0808082b0819, 0x192b0808082b1908, 0x192b080819080808, 0x192b080819081919, + 0x192b080819082b08, 0x192b080819190819, 0x192b080819191908, 0x192b0808192b0808, + 0x192b08082b081908, 0x192b08082b190808, 0x192b081908080808, 0x192b08190808082b, + 0x192b081908081919, 0x192b081908082b08, 0x192b081908190819, 0x192b081908191908, + 0x192b0819082b0808, 0x192b081919080819, 0x192b081919081908, 0x192b081919190808, + 0x192b08192b080808, 0x192b08192b192b19, 0x192b082b08081908, 0x192b082b08190808, + 0x192b082b19080808, 0x192b082b1919192b, 0x192b082b2b2b0819, 0x192b190808080808, + 0x192b190808081919, 0x192b190808082b08, 0x192b190808190819, 0x192b190808191908, + 0x192b1908082b0808, 0x192b190819080819, 0x192b190819081908, 0x192b190819190808, + 0x192b19082b080808, 0x192b191908080819, 0x192b191908081908, 0x192b191908190808, + 0x192b191919080808, 0x192b191919082b2b, 0x192b1919192b2b08, 0x192b19192b19082b, + 0x192b192b08080808, 0x192b192b2b191908, 0x192b2b0808080819, 0x192b2b0808081908, + 0x192b2b0808190808, 0x192b2b08192b1919, 0x192b2b082b192b08, 0x192b2b1908080808, + 0x192b2b19082b2b2b, 0x192b2b2b1908082b, 0x192b2b2b2b2b0819, 0x2b08080808080808, + 0x2b0808080808082b, 0x2b08080808081919, 0x2b08080808082b08, 0x2b08080808190819, + 0x2b08080808191908, 0x2b08080808192b19, 0x2b080808082b0808, 0x2b080808082b1919, + 0x2b08080819080819, 0x2b08080819081908, 0x2b08080819190808, 0x2b0808081919082b, + 0x2b08080819191919, 0x2b08080819192b08, 0x2b080808192b0819, 0x2b0808082b080808, + 0x2b0808082b081919, 0x2b0808082b190819, 0x2b0808082b191908, 0x2b08081908080819, + 0x2b08081908081908, 0x2b08081908082b19, 0x2b08081908190808, 0x2b0808190819082b, + 0x2b08081908191919, 0x2b08081908192b08, 0x2b080819082b0819, 0x2b080819082b1908, + 0x2b08081919080808, 0x2b0808191908082b, 0x2b08081919081919, 0x2b08081919082b08, + 0x2b08081919190819, 0x2b08081919191908, 0x2b0808192b080819, 0x2b0808192b081908, + 0x2b0808192b190808, 0x2b0808192b2b2b19, 0x2b08082b08080808, 0x2b08082b08081919, + 0x2b08082b08082b2b, 0x2b08082b08190819, 0x2b08082b08191908, 0x2b08082b19080819, + 0x2b08082b19081908, 0x2b08082b19190808, 0x2b08190808080819, 0x2b08190808081908, + 0x2b0819080808192b, 0x2b08190808082b19, 0x2b08190808190808, 0x2b0819080819082b, + 0x2b08190808191919, 0x2b08190808192b08, 0x2b081908082b0819, 0x2b08190819080808, + 0x2b0819081908082b, 0x2b08190819081919, 0x2b08190819082b08, 0x2b08190819190819, + 0x2b08190819191908, 0x2b081908192b0808, 0x2b0819082b080819, 0x2b0819082b081908, + 0x2b0819082b190808, 0x2b08191908080808, 0x2b0819190808082b, 0x2b08191908081919, + 0x2b08191908082b08, 0x2b08191908190819, 0x2b08191908191908, 0x2b081919082b0808, + 0x2b08191919080819, 0x2b08191919081908, 0x2b08191919190808, 0x2b0819192b080808, + 0x2b0819192b082b2b, 0x2b08192b08080819, 0x2b08192b08081908, 0x2b08192b08190808, + 0x2b08192b082b2b19, 0x2b08192b19080808, 0x2b082b0808080808, 0x2b082b0808081919, + 0x2b082b0808190819, 0x2b082b0808191908, 0x2b082b0819080819, 0x2b082b0819081908, + 0x2b082b0819190808, 0x2b082b082b2b082b, 0x2b082b1908080819, 0x2b082b1908081908, + 0x2b082b1919080808, 0x2b082b19192b1919, 0x2b082b2b082b082b, 0x2b082b2b19192b08, + 0x2b082b2b19192b2b, 0x2b082b2b2b08082b, 0x2b082b2b2b2b082b, 0x2b19080808080819, + 0x2b19080808081908, 0x2b19080808082b19, 0x2b19080808190808, 0x2b1908080819082b, + 0x2b19080808191919, 0x2b19080808192b08, 0x2b190808082b1908, 0x2b19080819080808, + 0x2b1908081908082b, 0x2b19080819081919, 0x2b19080819082b08, 0x2b19080819190819, + 0x2b19080819191908, 0x2b190808192b0808, 0x2b1908082b080819, 0x2b1908082b081908, + 0x2b1908082b190808, 0x2b19081908080808, 0x2b19081908081919, 0x2b19081908190819, + 0x2b19081908191908, 0x2b19081919080819, 0x2b19081919081908, 0x2b19081919190808, + 0x2b19081919192b2b, 0x2b19082b08080819, 0x2b19082b08081908, 0x2b19082b08190808, + 0x2b19082b19080808, 0x2b19082b2b2b192b, 0x2b19190808080808, 0x2b1919080808082b, + 0x2b19190808081919, 0x2b19190808082b08, 0x2b19190808190819, 0x2b19190808191908, + 0x2b191908082b0808, 0x2b19190819080819, 0x2b19190819081908, 0x2b19190819190808, + 0x2b1919082b080808, 0x2b1919082b19192b, 0x2b19191908080819, 0x2b19191908081908, + 0x2b19191908190808, 0x2b19191919080808, 0x2b1919192b192b08, 0x2b1919192b2b0819, + 0x2b19192b08080808, 0x2b19192b1908192b, 0x2b19192b192b1908, 0x2b192b0808080819, + 0x2b192b0808081908, 0x2b192b0808190808, 0x2b192b08082b192b, 0x2b192b0819080808, + 0x2b192b082b2b2b19, 0x2b192b1908080808, 0x2b192b1919082b19, 0x2b192b191919082b, + 0x2b192b2b2b190808, 0x2b2b080808080808, 0x2b2b080808081919, 0x2b2b080808082b2b, + 0x2b2b080808191908, 0x2b2b0808082b082b, 0x2b2b0808082b2b2b, 0x2b2b080819080819, + 0x2b2b080819081908, 0x2b2b080819190808, 0x2b2b08082b2b082b, 0x2b2b08082b2b2b2b, + 0x2b2b081919080808, 0x2b2b0819192b1919, 0x2b2b082b0808082b, 0x2b2b082b08082b2b, + 0x2b2b082b082b082b, 0x2b2b082b082b2b08, 0x2b2b082b082b2b2b, 0x2b2b082b2b08082b, + 0x2b2b082b2b082b08, 0x2b2b082b2b082b2b, 0x2b2b082b2b2b2b08, 0x2b2b190808080819, + 0x2b2b190808081908, 0x2b2b190808190808, 0x2b2b190819080808, 0x2b2b19082b082b19, + 0x2b2b19082b2b1908, 0x2b2b191908080808, 0x2b2b191908192b19, 0x2b2b192b19190819, + 0x2b2b2b0808082b2b, 0x2b2b2b08082b2b08, 0x2b2b2b082b2b082b, 0x2b2b2b1919191908, + 0x2b2b2b192b08192b, 0x2b2b2b2b08082b08, 0x2b2b2b2b08082b2b, 0x2b2b2b2b082b0808, + 0x2b2b2b2b082b082b, 0x2b2b2b2b082b2b08, 0x2b2b2b2b2b082b08, 0x2b2b2b2b2b2b2b2b, +GGML_TABLE_END() + +GGML_TABLE_BEGIN(uint32_t, iq3xxs_grid, 256) + 0x04040404, 0x04040414, 0x04040424, 0x04040c0c, 0x04040c1c, 0x04040c3e, 0x04041404, 0x04041414, + 0x04041c0c, 0x04042414, 0x04043e1c, 0x04043e2c, 0x040c040c, 0x040c041c, 0x040c0c04, 0x040c0c14, + 0x040c140c, 0x040c142c, 0x040c1c04, 0x040c1c14, 0x040c240c, 0x040c2c24, 0x040c3e04, 0x04140404, + 0x04140414, 0x04140424, 0x04140c0c, 0x04141404, 0x04141414, 0x04141c0c, 0x04141c1c, 0x04141c3e, + 0x04142c0c, 0x04142c3e, 0x04143e2c, 0x041c040c, 0x041c043e, 0x041c0c04, 0x041c0c14, 0x041c142c, + 0x041c3e04, 0x04240c1c, 0x04241c3e, 0x04242424, 0x04242c3e, 0x04243e1c, 0x04243e2c, 0x042c040c, + 0x042c043e, 0x042c1c14, 0x042c2c14, 0x04341c2c, 0x04343424, 0x043e0c04, 0x043e0c24, 0x043e0c34, + 0x043e241c, 0x043e340c, 0x0c04040c, 0x0c04041c, 0x0c040c04, 0x0c040c14, 0x0c04140c, 0x0c04141c, + 0x0c041c04, 0x0c041c14, 0x0c041c24, 0x0c04243e, 0x0c042c04, 0x0c0c0404, 0x0c0c0414, 0x0c0c0c0c, + 0x0c0c1404, 0x0c0c1414, 0x0c14040c, 0x0c14041c, 0x0c140c04, 0x0c140c14, 0x0c14140c, 0x0c141c04, + 0x0c143e14, 0x0c1c0404, 0x0c1c0414, 0x0c1c1404, 0x0c1c1c0c, 0x0c1c2434, 0x0c1c3434, 0x0c24040c, + 0x0c24042c, 0x0c242c04, 0x0c2c1404, 0x0c2c1424, 0x0c2c2434, 0x0c2c3e0c, 0x0c34042c, 0x0c3e1414, + 0x0c3e2404, 0x14040404, 0x14040414, 0x14040c0c, 0x14040c1c, 0x14041404, 0x14041414, 0x14041434, + 0x14041c0c, 0x14042414, 0x140c040c, 0x140c041c, 0x140c042c, 0x140c0c04, 0x140c0c14, 0x140c140c, + 0x140c1c04, 0x140c341c, 0x140c343e, 0x140c3e04, 0x14140404, 0x14140414, 0x14140c0c, 0x14140c3e, + 0x14141404, 0x14141414, 0x14141c3e, 0x14142404, 0x14142c2c, 0x141c040c, 0x141c0c04, 0x141c0c24, + 0x141c3e04, 0x141c3e24, 0x14241c2c, 0x14242c1c, 0x142c041c, 0x142c143e, 0x142c240c, 0x142c3e24, + 0x143e040c, 0x143e041c, 0x143e0c34, 0x143e242c, 0x1c04040c, 0x1c040c04, 0x1c040c14, 0x1c04140c, + 0x1c04141c, 0x1c042c04, 0x1c04342c, 0x1c043e14, 0x1c0c0404, 0x1c0c0414, 0x1c0c1404, 0x1c0c1c0c, + 0x1c0c2424, 0x1c0c2434, 0x1c14040c, 0x1c14041c, 0x1c140c04, 0x1c14142c, 0x1c142c14, 0x1c143e14, + 0x1c1c0c0c, 0x1c1c1c1c, 0x1c241c04, 0x1c24243e, 0x1c243e14, 0x1c2c0404, 0x1c2c0434, 0x1c2c1414, + 0x1c2c2c2c, 0x1c340c24, 0x1c341c34, 0x1c34341c, 0x1c3e1c1c, 0x1c3e3404, 0x24040424, 0x24040c3e, + 0x24041c2c, 0x24041c3e, 0x24042c1c, 0x24042c3e, 0x240c3e24, 0x24141404, 0x24141c3e, 0x24142404, + 0x24143404, 0x24143434, 0x241c043e, 0x241c242c, 0x24240424, 0x24242c0c, 0x24243424, 0x242c142c, + 0x242c241c, 0x242c3e04, 0x243e042c, 0x243e0c04, 0x243e0c14, 0x243e1c04, 0x2c040c14, 0x2c04240c, + 0x2c043e04, 0x2c0c0404, 0x2c0c0434, 0x2c0c1434, 0x2c0c2c2c, 0x2c140c24, 0x2c141c14, 0x2c143e14, + 0x2c1c0414, 0x2c1c2c1c, 0x2c240c04, 0x2c24141c, 0x2c24143e, 0x2c243e14, 0x2c2c0414, 0x2c2c1c0c, + 0x2c342c04, 0x2c3e1424, 0x2c3e2414, 0x34041424, 0x34042424, 0x34042434, 0x34043424, 0x340c140c, + 0x340c340c, 0x34140c3e, 0x34143424, 0x341c1c04, 0x341c1c34, 0x34242424, 0x342c042c, 0x342c2c14, + 0x34341c1c, 0x343e041c, 0x343e140c, 0x3e04041c, 0x3e04042c, 0x3e04043e, 0x3e040c04, 0x3e041c14, + 0x3e042c14, 0x3e0c1434, 0x3e0c2404, 0x3e140c14, 0x3e14242c, 0x3e142c14, 0x3e1c0404, 0x3e1c0c2c, + 0x3e1c1c1c, 0x3e1c3404, 0x3e24140c, 0x3e24240c, 0x3e2c0404, 0x3e2c0414, 0x3e2c1424, 0x3e341c04, +GGML_TABLE_END() + +GGML_TABLE_BEGIN(uint32_t, iq3s_grid, 512) + 0x01010101, 0x01010103, 0x01010105, 0x0101010b, 0x0101010f, 0x01010301, 0x01010303, 0x01010305, + 0x01010309, 0x0101030d, 0x01010501, 0x01010503, 0x0101050b, 0x01010707, 0x01010901, 0x01010905, + 0x0101090b, 0x0101090f, 0x01010b03, 0x01010b07, 0x01010d01, 0x01010d05, 0x01010f03, 0x01010f09, + 0x01010f0f, 0x01030101, 0x01030103, 0x01030105, 0x01030109, 0x01030301, 0x01030303, 0x0103030b, + 0x01030501, 0x01030507, 0x0103050f, 0x01030703, 0x0103070b, 0x01030909, 0x01030d03, 0x01030d0b, + 0x01030f05, 0x01050101, 0x01050103, 0x0105010b, 0x0105010f, 0x01050301, 0x01050307, 0x0105030d, + 0x01050503, 0x0105050b, 0x01050701, 0x01050709, 0x01050905, 0x0105090b, 0x0105090f, 0x01050b03, + 0x01050b07, 0x01050f01, 0x01050f07, 0x01070107, 0x01070303, 0x0107030b, 0x01070501, 0x01070505, + 0x01070703, 0x01070707, 0x0107070d, 0x01070909, 0x01070b01, 0x01070b05, 0x01070d0f, 0x01070f03, + 0x01070f0b, 0x01090101, 0x01090307, 0x0109030f, 0x01090503, 0x01090509, 0x01090705, 0x01090901, + 0x01090907, 0x01090b03, 0x01090f01, 0x010b0105, 0x010b0109, 0x010b0501, 0x010b0505, 0x010b050d, + 0x010b0707, 0x010b0903, 0x010b090b, 0x010b090f, 0x010b0d0d, 0x010b0f07, 0x010d010d, 0x010d0303, + 0x010d0307, 0x010d0703, 0x010d0b05, 0x010d0f03, 0x010f0101, 0x010f0105, 0x010f0109, 0x010f0501, + 0x010f0505, 0x010f050d, 0x010f0707, 0x010f0b01, 0x010f0b09, 0x03010101, 0x03010103, 0x03010105, + 0x03010109, 0x03010301, 0x03010303, 0x03010307, 0x0301030b, 0x0301030f, 0x03010501, 0x03010505, + 0x03010703, 0x03010709, 0x0301070d, 0x03010b09, 0x03010b0d, 0x03010d03, 0x03010f05, 0x03030101, + 0x03030103, 0x03030107, 0x0303010d, 0x03030301, 0x03030309, 0x03030503, 0x03030701, 0x03030707, + 0x03030903, 0x03030b01, 0x03030b05, 0x03030f01, 0x03030f0d, 0x03050101, 0x03050305, 0x0305030b, + 0x0305030f, 0x03050501, 0x03050509, 0x03050705, 0x03050901, 0x03050907, 0x03050b0b, 0x03050d01, + 0x03050f05, 0x03070103, 0x03070109, 0x0307010f, 0x03070301, 0x03070307, 0x03070503, 0x0307050f, + 0x03070701, 0x03070709, 0x03070903, 0x03070d05, 0x03070f01, 0x03090107, 0x0309010b, 0x03090305, + 0x03090309, 0x03090703, 0x03090707, 0x03090905, 0x0309090d, 0x03090b01, 0x03090b09, 0x030b0103, + 0x030b0301, 0x030b0307, 0x030b0503, 0x030b0701, 0x030b0705, 0x030b0b03, 0x030d0501, 0x030d0509, + 0x030d050f, 0x030d0909, 0x030d090d, 0x030f0103, 0x030f0107, 0x030f0301, 0x030f0305, 0x030f0503, + 0x030f070b, 0x030f0903, 0x030f0d05, 0x030f0f01, 0x05010101, 0x05010103, 0x05010107, 0x0501010b, + 0x0501010f, 0x05010301, 0x05010305, 0x05010309, 0x0501030d, 0x05010503, 0x05010507, 0x0501050f, + 0x05010701, 0x05010705, 0x05010903, 0x05010907, 0x0501090b, 0x05010b01, 0x05010b05, 0x05010d0f, + 0x05010f01, 0x05010f07, 0x05010f0b, 0x05030101, 0x05030105, 0x05030301, 0x05030307, 0x0503030f, + 0x05030505, 0x0503050b, 0x05030703, 0x05030709, 0x05030905, 0x05030b03, 0x05050103, 0x05050109, + 0x0505010f, 0x05050503, 0x05050507, 0x05050701, 0x0505070f, 0x05050903, 0x05050b07, 0x05050b0f, + 0x05050f03, 0x05050f09, 0x05070101, 0x05070105, 0x0507010b, 0x05070303, 0x05070505, 0x05070509, + 0x05070703, 0x05070707, 0x05070905, 0x05070b01, 0x05070d0d, 0x05090103, 0x0509010f, 0x05090501, + 0x05090507, 0x05090705, 0x0509070b, 0x05090903, 0x05090f05, 0x05090f0b, 0x050b0109, 0x050b0303, + 0x050b0505, 0x050b070f, 0x050b0901, 0x050b0b07, 0x050b0f01, 0x050d0101, 0x050d0105, 0x050d010f, + 0x050d0503, 0x050d0b0b, 0x050d0d03, 0x050f010b, 0x050f0303, 0x050f050d, 0x050f0701, 0x050f0907, + 0x050f0b01, 0x07010105, 0x07010303, 0x07010307, 0x0701030b, 0x0701030f, 0x07010505, 0x07010703, + 0x07010707, 0x0701070b, 0x07010905, 0x07010909, 0x0701090f, 0x07010b03, 0x07010d07, 0x07010f03, + 0x07030103, 0x07030107, 0x0703010b, 0x07030309, 0x07030503, 0x07030507, 0x07030901, 0x07030d01, + 0x07030f05, 0x07030f0d, 0x07050101, 0x07050305, 0x07050501, 0x07050705, 0x07050709, 0x07050b01, + 0x07070103, 0x07070301, 0x07070309, 0x07070503, 0x07070507, 0x0707050f, 0x07070701, 0x07070903, + 0x07070907, 0x0707090f, 0x07070b0b, 0x07070f07, 0x07090107, 0x07090303, 0x0709030d, 0x07090505, + 0x07090703, 0x07090b05, 0x07090d01, 0x07090d09, 0x070b0103, 0x070b0301, 0x070b0305, 0x070b050b, + 0x070b0705, 0x070b0909, 0x070b0b0d, 0x070b0f07, 0x070d030d, 0x070d0903, 0x070f0103, 0x070f0107, + 0x070f0501, 0x070f0505, 0x070f070b, 0x09010101, 0x09010109, 0x09010305, 0x09010501, 0x09010509, + 0x0901050f, 0x09010705, 0x09010903, 0x09010b01, 0x09010f01, 0x09030105, 0x0903010f, 0x09030303, + 0x09030307, 0x09030505, 0x09030701, 0x0903070b, 0x09030907, 0x09030b03, 0x09030b0b, 0x09050103, + 0x09050107, 0x09050301, 0x0905030b, 0x09050503, 0x09050707, 0x09050901, 0x09050b0f, 0x09050d05, + 0x09050f01, 0x09070109, 0x09070303, 0x09070307, 0x09070501, 0x09070505, 0x09070703, 0x0907070b, + 0x09090101, 0x09090105, 0x09090509, 0x0909070f, 0x09090901, 0x09090f03, 0x090b010b, 0x090b010f, + 0x090b0503, 0x090b0d05, 0x090d0307, 0x090d0709, 0x090d0d01, 0x090f0301, 0x090f030b, 0x090f0701, + 0x090f0907, 0x090f0b03, 0x0b010105, 0x0b010301, 0x0b010309, 0x0b010505, 0x0b010901, 0x0b010909, + 0x0b01090f, 0x0b010b05, 0x0b010d0d, 0x0b010f09, 0x0b030103, 0x0b030107, 0x0b03010b, 0x0b030305, + 0x0b030503, 0x0b030705, 0x0b030f05, 0x0b050101, 0x0b050303, 0x0b050507, 0x0b050701, 0x0b05070d, + 0x0b050b07, 0x0b070105, 0x0b07010f, 0x0b070301, 0x0b07050f, 0x0b070909, 0x0b070b03, 0x0b070d0b, + 0x0b070f07, 0x0b090103, 0x0b090109, 0x0b090501, 0x0b090705, 0x0b09090d, 0x0b0b0305, 0x0b0b050d, + 0x0b0b0b03, 0x0b0b0b07, 0x0b0d0905, 0x0b0f0105, 0x0b0f0109, 0x0b0f0505, 0x0d010303, 0x0d010307, + 0x0d01030b, 0x0d010703, 0x0d010707, 0x0d010d01, 0x0d030101, 0x0d030501, 0x0d03050f, 0x0d030d09, + 0x0d050305, 0x0d050709, 0x0d050905, 0x0d050b0b, 0x0d050d05, 0x0d050f01, 0x0d070101, 0x0d070309, + 0x0d070503, 0x0d070901, 0x0d09050b, 0x0d090907, 0x0d090d05, 0x0d0b0101, 0x0d0b0107, 0x0d0b0709, + 0x0d0b0d01, 0x0d0d010b, 0x0d0d0901, 0x0d0f0303, 0x0d0f0307, 0x0f010101, 0x0f010109, 0x0f01010f, + 0x0f010501, 0x0f010505, 0x0f01070d, 0x0f010901, 0x0f010b09, 0x0f010d05, 0x0f030105, 0x0f030303, + 0x0f030509, 0x0f030907, 0x0f03090b, 0x0f050103, 0x0f050109, 0x0f050301, 0x0f05030d, 0x0f050503, + 0x0f050701, 0x0f050b03, 0x0f070105, 0x0f070705, 0x0f07070b, 0x0f070b07, 0x0f090103, 0x0f09010b, + 0x0f090307, 0x0f090501, 0x0f090b01, 0x0f0b0505, 0x0f0b0905, 0x0f0d0105, 0x0f0d0703, 0x0f0f0101, +GGML_TABLE_END() + +#define NGRID_IQ1S 2048 +#define IQ1S_DELTA 0.125f +#define IQ1M_DELTA 0.125f +#if defined(GGML_COMMON_IMPL_C) +GGML_TABLE_BEGIN(uint64_t, iq1s_grid, NGRID_IQ1S) + 0xffffffffffffffff, 0xffffffffffffff01, 0xffffffffffff0000, 0xffffffffffff01ff, + 0xffffffffffff0101, 0xffffffffff00ff00, 0xffffffffff000000, 0xffffffffff01ffff, + 0xffffffffff01ff01, 0xffffffffff0101ff, 0xffffffffff010101, 0xffffffff00ff0000, + 0xffffffff0000ff00, 0xffffffff000000ff, 0xffffffff00000001, 0xffffffff00010000, + 0xffffffff01ffffff, 0xffffffff01ffff01, 0xffffffff01ff01ff, 0xffffffff01ff0101, + 0xffffffff01000000, 0xffffffff0101ffff, 0xffffffff0101ff01, 0xffffffff010101ff, + 0xffffffff01010101, 0xffffff00ffff00ff, 0xffffff00ffff0000, 0xffffff00ff00ff00, + 0xffffff00ff0000ff, 0xffffff00ff000001, 0xffffff00ff000100, 0xffffff00ff000101, + 0xffffff00ff010000, 0xffffff0000ffff00, 0xffffff0000ff0001, 0xffffff0000ff0100, + 0xffffff000000ff01, 0xffffff0000000000, 0xffffff0000000101, 0xffffff000001ff00, + 0xffffff00000100ff, 0xffffff0000010001, 0xffffff00000101ff, 0xffffff0001ff0000, + 0xffffff000100ff00, 0xffffff00010000ff, 0xffffff0001000001, 0xffffff0001010000, + 0xffffff01ffffffff, 0xffffff01ffffff01, 0xffffff01ffff01ff, 0xffffff01ffff0101, + 0xffffff01ff000000, 0xffffff01ff01ffff, 0xffffff01ff01ff01, 0xffffff01ff0101ff, + 0xffffff01ff010101, 0xffffff0100ff0000, 0xffffff010000ff00, 0xffffff0100000100, + 0xffffff01000100ff, 0xffffff0100010100, 0xffffff0101ffffff, 0xffffff0101ffff01, + 0xffffff0101ff01ff, 0xffffff0101ff0101, 0xffffff010100ff00, 0xffffff0101000000, + 0xffffff0101000100, 0xffffff010101ffff, 0xffffff010101ff01, 0xffffff01010101ff, + 0xffffff0101010101, 0xffff00ffff00ff00, 0xffff00ffff0000ff, 0xffff00ffff000001, + 0xffff00ffff010000, 0xffff00ff00ffff00, 0xffff00ff00ff0100, 0xffff00ff00000000, + 0xffff00ff00000101, 0xffff00ff000100ff, 0xffff00ff00010000, 0xffff00ff0100ff00, + 0xffff00ff01000100, 0xffff00ff01010000, 0xffff0000ffffff00, 0xffff0000ffff00ff, + 0xffff0000ffff0000, 0xffff0000ffff0001, 0xffff0000ff000000, 0xffff0000ff0001ff, + 0xffff0000ff000101, 0xffff0000ff010100, 0xffff000000ffffff, 0xffff000000ff0000, + 0xffff000000ff0101, 0xffff00000000ffff, 0xffff00000000ff00, 0xffff0000000000ff, + 0xffff000000000000, 0xffff000000000001, 0xffff000000000100, 0xffff00000001ffff, + 0xffff00000001ff01, 0xffff000000010000, 0xffff0000000101ff, 0xffff000000010101, + 0xffff000001ffff00, 0xffff00000100ff00, 0xffff000001000000, 0xffff0000010001ff, + 0xffff000001000101, 0xffff00000101ff00, 0xffff0000010100ff, 0xffff000001010000, + 0xffff000001010001, 0xffff000001010100, 0xffff0001ff0000ff, 0xffff0001ff000100, + 0xffff000100ffff00, 0xffff000100ff00ff, 0xffff00010000ffff, 0xffff00010000ff01, + 0xffff000100000000, 0xffff0001000001ff, 0xffff00010001ffff, 0xffff00010001ff00, + 0xffff000100010001, 0xffff000100010100, 0xffff000101ff0000, 0xffff00010100ff00, + 0xffff0001010000ff, 0xffff000101000100, 0xffff01ffffffffff, 0xffff01ffffffff01, + 0xffff01ffffff01ff, 0xffff01ffffff0101, 0xffff01ffff000000, 0xffff01ffff01ffff, + 0xffff01ffff01ff01, 0xffff01ffff0101ff, 0xffff01ffff010101, 0xffff01ff00ff0000, + 0xffff01ff0000ff00, 0xffff01ff00000001, 0xffff01ff00010000, 0xffff01ff01ffffff, + 0xffff01ff01ffff01, 0xffff01ff01ff01ff, 0xffff01ff01ff0101, 0xffff01ff01000000, + 0xffff01ff0101ffff, 0xffff01ff0101ff01, 0xffff01ff010101ff, 0xffff01ff01010101, + 0xffff0100ffff0000, 0xffff0100ff00ff00, 0xffff0100ff0000ff, 0xffff0100ff000100, + 0xffff0100ff0100ff, 0xffff0100ff010000, 0xffff010000ffff00, 0xffff01000000ffff, + 0xffff01000000ff00, 0xffff010000000000, 0xffff01000001ff00, 0xffff0100000100ff, + 0xffff010000010100, 0xffff01000100ff00, 0xffff0100010000ff, 0xffff010001000001, + 0xffff010001000100, 0xffff010001010000, 0xffff0101ffffffff, 0xffff0101ffffff01, + 0xffff0101ffff01ff, 0xffff0101ffff0101, 0xffff0101ff000000, 0xffff0101ff01ffff, + 0xffff0101ff01ff01, 0xffff0101ff0101ff, 0xffff0101ff010101, 0xffff010100ff0000, + 0xffff01010000ff00, 0xffff010100000100, 0xffff01010001ff00, 0xffff010100010000, + 0xffff010101ffffff, 0xffff010101ffff01, 0xffff010101ff0000, 0xffff010101ff01ff, + 0xffff010101ff0101, 0xffff010101000000, 0xffff01010101ffff, 0xffff01010101ff01, + 0xffff0101010101ff, 0xffff010101010101, 0xff00ffffff00ffff, 0xff00ffffff00ff00, + 0xff00ffffff0000ff, 0xff00ffffff000100, 0xff00ffffff0100ff, 0xff00ffffff010000, + 0xff00ffff00ffff00, 0xff00ffff00ff00ff, 0xff00ffff0000ffff, 0xff00ffff00000000, + 0xff00ffff000001ff, 0xff00ffff0001ff00, 0xff00ffff000100ff, 0xff00ffff00010000, + 0xff00ffff00010100, 0xff00ffff0100ff00, 0xff00ffff010000ff, 0xff00ffff01000001, + 0xff00ffff0101ff00, 0xff00ffff01010000, 0xff00ff00ffffff00, 0xff00ff00ffff00ff, + 0xff00ff00ffff0001, 0xff00ff00ffff0100, 0xff00ff00ff00ffff, 0xff00ff00ff00ff01, + 0xff00ff00ff000000, 0xff00ff00ff0001ff, 0xff00ff00ff01ff00, 0xff00ff00ff0100ff, + 0xff00ff00ff010100, 0xff00ff0000ff0000, 0xff00ff0000ff0101, 0xff00ff000000ffff, + 0xff00ff000000ff00, 0xff00ff000000ff01, 0xff00ff00000000ff, 0xff00ff0000000000, + 0xff00ff0000000001, 0xff00ff0000000100, 0xff00ff000001ffff, 0xff00ff0000010000, + 0xff00ff0001ff00ff, 0xff00ff000100ff01, 0xff00ff0001000000, 0xff00ff000101ff00, + 0xff00ff00010100ff, 0xff00ff01ff00ff00, 0xff00ff01ff0000ff, 0xff00ff01ff000001, + 0xff00ff01ff010000, 0xff00ff0100ffffff, 0xff00ff0100ff0001, 0xff00ff0100ff0100, + 0xff00ff010000ff01, 0xff00ff0100000000, 0xff00ff01000001ff, 0xff00ff0100000101, + 0xff00ff01000100ff, 0xff00ff0100010001, 0xff00ff0101ff0000, 0xff00ff010100ff00, + 0xff00ff01010000ff, 0xff00ff0101000001, 0xff00ff0101010000, 0xff0000ffffffff00, + 0xff0000ffffff0001, 0xff0000ffffff0100, 0xff0000ffff0000ff, 0xff0000ffff000000, + 0xff0000ffff0001ff, 0xff0000ffff000100, 0xff0000ffff01ff00, 0xff0000ffff010001, + 0xff0000ff00ffff00, 0xff0000ff00ff0000, 0xff0000ff00ff0001, 0xff0000ff00ff01ff, + 0xff0000ff00ff0101, 0xff0000ff0000ff00, 0xff0000ff000000ff, 0xff0000ff00000000, + 0xff0000ff00000001, 0xff0000ff00000100, 0xff0000ff0001ff01, 0xff0000ff00010000, + 0xff0000ff000101ff, 0xff0000ff01ff00ff, 0xff0000ff01ff0100, 0xff0000ff0100ffff, + 0xff0000ff010000ff, 0xff0000ff01000000, 0xff0000ff010001ff, 0xff0000ff01000100, + 0xff0000ff01000101, 0xff0000ff0101ff00, 0xff0000ff010100ff, 0xff0000ff01010000, + 0xff0000ff01010100, 0xff000000ffffff01, 0xff000000ffff0000, 0xff000000ffff0101, + 0xff000000ff00ff00, 0xff000000ff0000ff, 0xff000000ff000000, 0xff000000ff000001, + 0xff000000ff000100, 0xff000000ff01ffff, 0xff000000ff01ff01, 0xff000000ff010000, + 0xff000000ff0101ff, 0xff000000ff010101, 0xff00000000ffff00, 0xff00000000ff00ff, + 0xff00000000ff0000, 0xff00000000ff0001, 0xff0000000000ff00, 0xff0000000000ff01, + 0xff000000000000ff, 0xff00000000000000, 0xff00000000000001, 0xff00000000000100, + 0xff00000000000101, 0xff0000000001ff00, 0xff000000000100ff, 0xff00000000010000, + 0xff00000000010001, 0xff00000000010100, 0xff00000001ffffff, 0xff00000001ffff01, + 0xff00000001ff00ff, 0xff00000001ff0000, 0xff00000001ff01ff, 0xff00000001ff0101, + 0xff0000000100ffff, 0xff0000000100ff00, 0xff000000010000ff, 0xff00000001000000, + 0xff00000001000001, 0xff00000001000100, 0xff00000001000101, 0xff0000000101ffff, + 0xff0000000101ff01, 0xff00000001010000, 0xff000001ffffff00, 0xff000001ffff00ff, + 0xff000001ffff0000, 0xff000001ffff0001, 0xff000001ff000000, 0xff000001ff000001, + 0xff000001ff0001ff, 0xff000001ff000101, 0xff000001ff01ff00, 0xff000001ff010001, + 0xff00000100ffffff, 0xff00000100ffff01, 0xff00000100ff00ff, 0xff00000100ff0000, + 0xff00000100ff01ff, 0xff00000100ff0101, 0xff0000010000ff00, 0xff00000100000000, + 0xff00000100000001, 0xff000001000001ff, 0xff00000100000100, 0xff0000010001ff00, + 0xff000001000100ff, 0xff00000100010000, 0xff000001000101ff, 0xff00000100010100, + 0xff00000100010101, 0xff00000101ff0001, 0xff00000101ff0101, 0xff0000010100ff01, + 0xff00000101000000, 0xff000001010100ff, 0xff00000101010100, 0xff0001ffff00ff00, + 0xff0001ffff000001, 0xff0001ffff010000, 0xff0001ff00ffff00, 0xff0001ff00ff00ff, + 0xff0001ff00ff0001, 0xff0001ff00ff0100, 0xff0001ff0000ffff, 0xff0001ff00000000, + 0xff0001ff000001ff, 0xff0001ff00000101, 0xff0001ff0001ffff, 0xff0001ff0001ff00, + 0xff0001ff000100ff, 0xff0001ff00010001, 0xff0001ff00010100, 0xff0001ff01ff0000, + 0xff0001ff0100ff00, 0xff0001ff010000ff, 0xff0001ff01010000, 0xff000100ff00ffff, + 0xff000100ff00ff01, 0xff000100ff000000, 0xff000100ff000101, 0xff000100ff01ff00, + 0xff000100ff010000, 0xff00010000ffff01, 0xff00010000ff00ff, 0xff00010000ff0000, + 0xff00010000ff01ff, 0xff0001000000ff00, 0xff000100000000ff, 0xff00010000000000, + 0xff00010000000001, 0xff00010000000100, 0xff00010000000101, 0xff0001000001ffff, + 0xff00010000010000, 0xff00010000010101, 0xff00010001ff0100, 0xff0001000100ff00, + 0xff0001000100ff01, 0xff00010001000000, 0xff000100010001ff, 0xff0001000101ff00, + 0xff00010001010001, 0xff00010001010100, 0xff000101ffff0100, 0xff000101ff000001, + 0xff000101ff0100ff, 0xff000101ff010001, 0xff00010100ff00ff, 0xff00010100ff0001, + 0xff00010100ff0100, 0xff0001010000ffff, 0xff0001010000ff01, 0xff00010100000000, + 0xff000101000001ff, 0xff0001010001ff00, 0xff00010100010001, 0xff00010100010100, + 0xff00010101ff0000, 0xff0001010100ff00, 0xff00010101000001, 0xff00010101000101, + 0xff01ffffffffffff, 0xff01ffffffffff01, 0xff01ffffffff01ff, 0xff01ffffffff0101, + 0xff01ffffff000000, 0xff01ffffff01ffff, 0xff01ffffff01ff01, 0xff01ffffff010000, + 0xff01ffffff0101ff, 0xff01ffffff010101, 0xff01ffff00ff0000, 0xff01ffff0000ff00, + 0xff01ffff00000100, 0xff01ffff0001ff00, 0xff01ffff00010000, 0xff01ffff01ffffff, + 0xff01ffff01ffff01, 0xff01ffff01ff01ff, 0xff01ffff01ff0101, 0xff01ffff01000000, + 0xff01ffff0101ffff, 0xff01ffff0101ff01, 0xff01ffff01010000, 0xff01ffff010101ff, + 0xff01ffff01010101, 0xff01ff00ffff0000, 0xff01ff00ff00ff00, 0xff01ff00ff0000ff, + 0xff01ff00ff000100, 0xff01ff00ff010000, 0xff01ff0000ffff01, 0xff01ff0000ff00ff, + 0xff01ff0000ff0100, 0xff01ff0000000000, 0xff01ff00000001ff, 0xff01ff0000000101, + 0xff01ff000001ff00, 0xff01ff00000100ff, 0xff01ff0000010000, 0xff01ff0000010001, + 0xff01ff0001ff0000, 0xff01ff000100ffff, 0xff01ff0001000001, 0xff01ff0001000100, + 0xff01ff0001010000, 0xff01ff01ffffff00, 0xff01ff01ffff01ff, 0xff01ff01ffff0101, + 0xff01ff01ff00ff00, 0xff01ff01ff000000, 0xff01ff01ff01ffff, 0xff01ff01ff01ff01, + 0xff01ff01ff0101ff, 0xff01ff01ff010101, 0xff01ff0100ff0000, 0xff01ff010000ff00, + 0xff01ff0100000001, 0xff01ff0100000100, 0xff01ff0100010000, 0xff01ff0101ffff00, + 0xff01ff0101ff01ff, 0xff01ff0101ff0101, 0xff01ff010100ff00, 0xff01ff0101000000, + 0xff01ff010101ffff, 0xff01ff010101ff01, 0xff01ff01010101ff, 0xff01ff0101010101, + 0xff0100ffffff0000, 0xff0100ffff0000ff, 0xff0100ffff000001, 0xff0100ffff000100, + 0xff0100ffff010000, 0xff0100ff00ff00ff, 0xff0100ff00ff0000, 0xff0100ff00ff0001, + 0xff0100ff00ff0100, 0xff0100ff0000ff01, 0xff0100ff00000000, 0xff0100ff000001ff, + 0xff0100ff00000101, 0xff0100ff00010001, 0xff0100ff01ff0000, 0xff0100ff0100ff00, + 0xff0100ff010000ff, 0xff0100ff01000100, 0xff0100ff0101ff00, 0xff0100ff01010000, + 0xff010000ffff0100, 0xff010000ff000000, 0xff010000ff01ff00, 0xff010000ff010100, + 0xff01000000ffffff, 0xff01000000ff0000, 0xff01000000ff01ff, 0xff0100000000ff00, + 0xff010000000000ff, 0xff01000000000000, 0xff01000000000100, 0xff0100000001ff01, + 0xff01000000010000, 0xff010000000101ff, 0xff01000001ff0100, 0xff0100000100ffff, + 0xff010000010000ff, 0xff01000001000000, 0xff010000010001ff, 0xff01000001000101, + 0xff0100000101ff00, 0xff010000010100ff, 0xff01000001010001, 0xff01000001010100, + 0xff010001ffff0000, 0xff010001ff00ffff, 0xff010001ff00ff01, 0xff010001ff000100, + 0xff010001ff010000, 0xff01000100ffff00, 0xff01000100ff0100, 0xff01000100000000, + 0xff0100010001ffff, 0xff0100010001ff00, 0xff01000100010100, 0xff01000101ff00ff, + 0xff01000101ff0001, 0xff0100010100ffff, 0xff01000101000101, 0xff0101ffffffffff, + 0xff0101ffffffff01, 0xff0101ffffff01ff, 0xff0101ffffff0101, 0xff0101ffff000000, + 0xff0101ffff01ffff, 0xff0101ffff01ff01, 0xff0101ffff0101ff, 0xff0101ffff010101, + 0xff0101ff00ff0000, 0xff0101ff0000ff00, 0xff0101ff000000ff, 0xff0101ff00010000, + 0xff0101ff01ffffff, 0xff0101ff01ffff01, 0xff0101ff01ff01ff, 0xff0101ff01ff0101, + 0xff0101ff0101ffff, 0xff0101ff0101ff01, 0xff0101ff010101ff, 0xff0101ff01010101, + 0xff010100ffff0100, 0xff010100ff00ff00, 0xff010100ff0000ff, 0xff010100ff000100, + 0xff010100ff010000, 0xff01010000ff0001, 0xff01010000ff0100, 0xff0101000000ff01, + 0xff01010000000000, 0xff0101000001ff00, 0xff010100000100ff, 0xff01010000010001, + 0xff01010000010100, 0xff01010001ff0000, 0xff0101000100ffff, 0xff01010001000001, + 0xff01010001000100, 0xff010100010100ff, 0xff01010001010000, 0xff010101ffffffff, + 0xff010101ffffff01, 0xff010101ffff01ff, 0xff010101ffff0101, 0xff010101ff01ffff, + 0xff010101ff01ff01, 0xff010101ff0101ff, 0xff010101ff010101, 0xff01010100ff0000, + 0xff0101010000ff00, 0xff01010100000001, 0xff01010100000100, 0xff01010100010000, + 0xff01010101ffffff, 0xff01010101ffff01, 0xff01010101ff01ff, 0xff01010101ff0101, + 0xff01010101000000, 0xff0101010101ffff, 0xff0101010101ff01, 0xff010101010101ff, + 0xff01010101010101, 0x00ffffffffff0000, 0x00ffffffff00ff00, 0x00ffffffff000001, + 0x00ffffffff010000, 0x00ffffff00ff0100, 0x00ffffff0000ff01, 0x00ffffff00000000, + 0x00ffffff000001ff, 0x00ffffff00000101, 0x00ffffff0001ff00, 0x00ffffff000100ff, + 0x00ffffff00010001, 0x00ffffff010000ff, 0x00ffffff01000100, 0x00ffffff0101ff00, + 0x00ffffff01010001, 0x00ffff00ffffffff, 0x00ffff00ffffff00, 0x00ffff00ffff00ff, + 0x00ffff00ffff0001, 0x00ffff00ffff0100, 0x00ffff00ff00ff01, 0x00ffff00ff000000, + 0x00ffff00ff000001, 0x00ffff00ff0001ff, 0x00ffff00ff000101, 0x00ffff00ff01ff00, + 0x00ffff00ff010001, 0x00ffff00ff010100, 0x00ffff0000ff0000, 0x00ffff0000ff01ff, + 0x00ffff0000ff0101, 0x00ffff000000ff00, 0x00ffff00000000ff, 0x00ffff0000000000, + 0x00ffff0000000001, 0x00ffff0000000100, 0x00ffff0000000101, 0x00ffff0000010000, + 0x00ffff00000101ff, 0x00ffff0000010101, 0x00ffff0001ffff00, 0x00ffff0001ff00ff, + 0x00ffff0001ff0001, 0x00ffff000100ffff, 0x00ffff000100ff01, 0x00ffff0001000000, + 0x00ffff000101ffff, 0x00ffff000101ff00, 0x00ffff000101ff01, 0x00ffff01ffff0000, + 0x00ffff01ff00ff00, 0x00ffff01ff0000ff, 0x00ffff01ff000001, 0x00ffff01ff010000, + 0x00ffff0100ffff00, 0x00ffff010000ff01, 0x00ffff0100000000, 0x00ffff0100000101, + 0x00ffff01000100ff, 0x00ffff0100010100, 0x00ffff0101ff0100, 0x00ffff01010000ff, + 0x00ffff0101010000, 0x00ff00ffffffff00, 0x00ff00ffff000000, 0x00ff00ffff000100, + 0x00ff00ffff010100, 0x00ff00ff00ff0000, 0x00ff00ff00ff01ff, 0x00ff00ff00ff0101, + 0x00ff00ff0000ff00, 0x00ff00ff000000ff, 0x00ff00ff00000000, 0x00ff00ff00000001, + 0x00ff00ff0001ff00, 0x00ff00ff0001ff01, 0x00ff00ff00010000, 0x00ff00ff000101ff, + 0x00ff00ff00010101, 0x00ff00ff01ffff00, 0x00ff00ff01ff0001, 0x00ff00ff01ff0100, + 0x00ff00ff0100ffff, 0x00ff00ff0100ff01, 0x00ff00ff01000000, 0x00ff00ff0101ffff, + 0x00ff00ff0101ff00, 0x00ff00ff01010100, 0x00ff0000ffffff00, 0x00ff0000ffffff01, + 0x00ff0000ffff0000, 0x00ff0000ffff0101, 0x00ff0000ff00ff00, 0x00ff0000ff0000ff, + 0x00ff0000ff000000, 0x00ff0000ff000001, 0x00ff0000ff000100, 0x00ff0000ff01ffff, + 0x00ff0000ff010000, 0x00ff0000ff010101, 0x00ff000000ffff00, 0x00ff000000ff00ff, + 0x00ff000000ff0000, 0x00ff000000ff0001, 0x00ff000000ff0100, 0x00ff00000000ffff, + 0x00ff00000000ff00, 0x00ff0000000000ff, 0x00ff000000000000, 0x00ff000000000001, + 0x00ff0000000001ff, 0x00ff000000000100, 0x00ff00000001ff00, 0x00ff0000000100ff, + 0x00ff000000010000, 0x00ff000000010001, 0x00ff000000010100, 0x00ff000001ffff01, + 0x00ff000001ff00ff, 0x00ff000001ff0000, 0x00ff000001ff01ff, 0x00ff00000100ff00, + 0x00ff0000010000ff, 0x00ff000001000000, 0x00ff000001000001, 0x00ff000001000100, + 0x00ff000001000101, 0x00ff000001010000, 0x00ff0000010101ff, 0x00ff000001010101, + 0x00ff0001ffffff00, 0x00ff0001ffff0000, 0x00ff0001ffff0100, 0x00ff0001ff0000ff, + 0x00ff0001ff000000, 0x00ff0001ff0001ff, 0x00ff0001ff000101, 0x00ff0001ff01ff00, + 0x00ff0001ff0100ff, 0x00ff0001ff010100, 0x00ff000100ffffff, 0x00ff000100ffff01, + 0x00ff000100ff0000, 0x00ff000100ff01ff, 0x00ff00010000ffff, 0x00ff00010000ff00, + 0x00ff00010000ff01, 0x00ff000100000000, 0x00ff000100000001, 0x00ff000100000100, + 0x00ff00010001ff01, 0x00ff000100010000, 0x00ff0001000101ff, 0x00ff000101ffff00, + 0x00ff000101ff0000, 0x00ff000101ff0101, 0x00ff0001010000ff, 0x00ff000101000000, + 0x00ff00010101ff00, 0x00ff0001010100ff, 0x00ff000101010001, 0x00ff01ffffff0000, + 0x00ff01ffff00ff00, 0x00ff01ffff000000, 0x00ff01ffff000101, 0x00ff01ffff010000, + 0x00ff01ff00ffff01, 0x00ff01ff00ff0100, 0x00ff01ff0000ffff, 0x00ff01ff00000000, + 0x00ff01ff000001ff, 0x00ff01ff0001ff00, 0x00ff01ff000100ff, 0x00ff01ff00010001, + 0x00ff01ff00010100, 0x00ff01ff01ff0000, 0x00ff01ff0100ff00, 0x00ff01ff010000ff, + 0x00ff01ff01000001, 0x00ff01ff01000100, 0x00ff01ff01010000, 0x00ff0100ffffff00, + 0x00ff0100ffff0000, 0x00ff0100ffff0001, 0x00ff0100ffff0101, 0x00ff0100ff00ffff, + 0x00ff0100ff0000ff, 0x00ff0100ff000000, 0x00ff0100ff0001ff, 0x00ff0100ff01ff00, + 0x00ff0100ff0100ff, 0x00ff0100ff010001, 0x00ff010000ffffff, 0x00ff010000ff0000, + 0x00ff010000ff0101, 0x00ff01000000ff00, 0x00ff01000000ff01, 0x00ff0100000000ff, + 0x00ff010000000000, 0x00ff010000000001, 0x00ff010000000100, 0x00ff01000001ffff, + 0x00ff01000001ff01, 0x00ff010000010000, 0x00ff010000010001, 0x00ff010000010101, + 0x00ff010001ff0001, 0x00ff010001ff0100, 0x00ff01000100ff01, 0x00ff010001000000, + 0x00ff010001000001, 0x00ff0100010001ff, 0x00ff01000101ff00, 0x00ff0100010100ff, + 0x00ff010001010001, 0x00ff010001010100, 0x00ff0101ff000001, 0x00ff010100ff00ff, + 0x00ff010100ff0001, 0x00ff010100ff0100, 0x00ff010100000000, 0x00ff0101000001ff, + 0x00ff010100000101, 0x00ff0101000100ff, 0x00ff010100010100, 0x00ff0101010000ff, + 0x00ff010101010000, 0x0000ffffffffff00, 0x0000ffffffff00ff, 0x0000ffffffff0000, + 0x0000ffffffff0001, 0x0000ffffffff0100, 0x0000ffffff00ff01, 0x0000ffffff000000, + 0x0000ffffff000101, 0x0000ffffff01ff00, 0x0000ffffff0100ff, 0x0000ffffff010100, + 0x0000ffff00ffffff, 0x0000ffff00ff0000, 0x0000ffff00ff01ff, 0x0000ffff0000ff00, + 0x0000ffff000000ff, 0x0000ffff00000000, 0x0000ffff00000001, 0x0000ffff00000100, + 0x0000ffff00010000, 0x0000ffff000101ff, 0x0000ffff01ff0001, 0x0000ffff01ff0100, + 0x0000ffff01000000, 0x0000ffff010001ff, 0x0000ffff0101ffff, 0x0000ffff0101ff00, + 0x0000ffff01010001, 0x0000ffff01010100, 0x0000ff00ffff0000, 0x0000ff00ffff01ff, + 0x0000ff00ffff0100, 0x0000ff00ffff0101, 0x0000ff00ff00ff00, 0x0000ff00ff0000ff, + 0x0000ff00ff000000, 0x0000ff00ff000001, 0x0000ff00ff0001ff, 0x0000ff00ff000100, + 0x0000ff00ff01ffff, 0x0000ff00ff010000, 0x0000ff00ff010001, 0x0000ff00ff0101ff, + 0x0000ff00ff010101, 0x0000ff0000ffff00, 0x0000ff0000ff00ff, 0x0000ff0000ff0000, + 0x0000ff0000ff0001, 0x0000ff0000ff0100, 0x0000ff000000ffff, 0x0000ff000000ff00, + 0x0000ff000000ff01, 0x0000ff00000000ff, 0x0000ff0000000000, 0x0000ff0000000001, + 0x0000ff00000001ff, 0x0000ff0000000100, 0x0000ff0000000101, 0x0000ff000001ff00, + 0x0000ff00000100ff, 0x0000ff0000010000, 0x0000ff0000010001, 0x0000ff0000010100, + 0x0000ff0001ffff01, 0x0000ff0001ff0000, 0x0000ff000100ff00, 0x0000ff00010000ff, + 0x0000ff0001000000, 0x0000ff0001000001, 0x0000ff0001000100, 0x0000ff000101ffff, + 0x0000ff0001010000, 0x0000ff0001010101, 0x0000ff01ffffff00, 0x0000ff01ffff0001, + 0x0000ff01ff00ff01, 0x0000ff01ff000000, 0x0000ff01ff000101, 0x0000ff01ff01ff00, + 0x0000ff01ff0100ff, 0x0000ff0100ffff01, 0x0000ff0100ff0000, 0x0000ff0100ff0101, + 0x0000ff010000ff00, 0x0000ff01000000ff, 0x0000ff0100000000, 0x0000ff0100000001, + 0x0000ff0100000100, 0x0000ff010001ff01, 0x0000ff0100010000, 0x0000ff0101ff0000, + 0x0000ff010100ffff, 0x0000ff010100ff01, 0x0000ff0101000000, 0x0000ff0101000100, + 0x0000ff0101000101, 0x0000ff01010100ff, 0x000000ffffff00ff, 0x000000ffffff0000, + 0x000000ffff00ff00, 0x000000ffff0000ff, 0x000000ffff000000, 0x000000ffff000001, + 0x000000ffff0001ff, 0x000000ffff000100, 0x000000ffff01ff00, 0x000000ffff010000, + 0x000000ffff0101ff, 0x000000ffff010101, 0x000000ff00ffff00, 0x000000ff00ff00ff, + 0x000000ff00ff0000, 0x000000ff00ff0001, 0x000000ff00ff0100, 0x000000ff00ff0101, + 0x000000ff0000ffff, 0x000000ff0000ff00, 0x000000ff000000ff, 0x000000ff00000000, + 0x000000ff00000001, 0x000000ff000001ff, 0x000000ff00000100, 0x000000ff00000101, + 0x000000ff0001ff00, 0x000000ff0001ff01, 0x000000ff000100ff, 0x000000ff00010000, + 0x000000ff00010001, 0x000000ff00010100, 0x000000ff01ffffff, 0x000000ff01ff01ff, + 0x000000ff01ff0101, 0x000000ff0100ff00, 0x000000ff010000ff, 0x000000ff01000000, + 0x000000ff01000001, 0x000000ff01000100, 0x000000ff0101ff00, 0x000000ff010100ff, + 0x000000ff01010000, 0x000000ff01010101, 0x00000000ffffff00, 0x00000000ffffff01, + 0x00000000ffff00ff, 0x00000000ffff0000, 0x00000000ffff0001, 0x00000000ffff0100, + 0x00000000ff00ffff, 0x00000000ff00ff00, 0x00000000ff00ff01, 0x00000000ff0000ff, + 0x00000000ff000000, 0x00000000ff000001, 0x00000000ff000100, 0x00000000ff000101, + 0x00000000ff01ff00, 0x00000000ff0100ff, 0x00000000ff010000, 0x00000000ff010001, + 0x00000000ff010100, 0x0000000000ffffff, 0x0000000000ffff00, 0x0000000000ffff01, + 0x0000000000ff00ff, 0x0000000000ff0000, 0x0000000000ff0001, 0x0000000000ff01ff, + 0x0000000000ff0100, 0x000000000000ffff, 0x000000000000ff00, 0x000000000000ff01, + 0x00000000000000ff, 0x0000000000000000, 0x0000000000000001, 0x00000000000001ff, + 0x0000000000000100, 0x0000000000000101, 0x000000000001ffff, 0x000000000001ff00, + 0x00000000000100ff, 0x0000000000010000, 0x0000000000010001, 0x00000000000101ff, + 0x0000000000010100, 0x0000000000010101, 0x0000000001ffff00, 0x0000000001ff00ff, + 0x0000000001ff0000, 0x0000000001ff0100, 0x0000000001ff0101, 0x000000000100ffff, + 0x000000000100ff00, 0x00000000010000ff, 0x0000000001000000, 0x0000000001000001, + 0x00000000010001ff, 0x0000000001000100, 0x000000000101ff00, 0x00000000010100ff, + 0x0000000001010000, 0x0000000001010001, 0x0000000001010100, 0x00000001ffffffff, + 0x00000001ffffff00, 0x00000001ffffff01, 0x00000001ffff00ff, 0x00000001ffff0001, + 0x00000001ffff01ff, 0x00000001ffff0100, 0x00000001ff00ff00, 0x00000001ff0000ff, + 0x00000001ff000000, 0x00000001ff0001ff, 0x00000001ff000100, 0x00000001ff01ffff, + 0x00000001ff01ff00, 0x00000001ff01ff01, 0x00000001ff0100ff, 0x00000001ff010000, + 0x00000001ff010001, 0x00000001ff0101ff, 0x00000001ff010100, 0x0000000100ffff00, + 0x0000000100ff0000, 0x0000000100ff0001, 0x0000000100ff01ff, 0x0000000100ff0100, + 0x0000000100ff0101, 0x000000010000ffff, 0x000000010000ff00, 0x000000010000ff01, + 0x00000001000000ff, 0x0000000100000000, 0x0000000100000001, 0x00000001000001ff, + 0x0000000100000100, 0x0000000100000101, 0x000000010001ff00, 0x00000001000100ff, + 0x0000000100010000, 0x0000000100010100, 0x0000000101ffff01, 0x0000000101ff0000, + 0x0000000101ff0001, 0x0000000101ff01ff, 0x0000000101ff0100, 0x0000000101ff0101, + 0x000000010100ff00, 0x0000000101000000, 0x0000000101000101, 0x000000010101ff01, + 0x0000000101010000, 0x0000000101010001, 0x00000001010101ff, 0x0000000101010100, + 0x000001ffffff00ff, 0x000001ffffff0000, 0x000001ffffff0001, 0x000001ffffff0100, + 0x000001ffff00ffff, 0x000001ffff000000, 0x000001ffff0001ff, 0x000001ffff01ff00, + 0x000001ffff010101, 0x000001ff00ff0000, 0x000001ff00ff01ff, 0x000001ff00ff0101, + 0x000001ff0000ff00, 0x000001ff000000ff, 0x000001ff00000000, 0x000001ff00000001, + 0x000001ff000001ff, 0x000001ff00000100, 0x000001ff0001ffff, 0x000001ff0001ff01, + 0x000001ff000100ff, 0x000001ff00010000, 0x000001ff01ffff01, 0x000001ff01ff0100, + 0x000001ff0100ffff, 0x000001ff0100ff01, 0x000001ff01000000, 0x000001ff010001ff, + 0x000001ff0101ff00, 0x000001ff01010100, 0x00000100ffffff00, 0x00000100ffffff01, + 0x00000100ffff0000, 0x00000100ffff0101, 0x00000100ff00ff00, 0x00000100ff0000ff, + 0x00000100ff000000, 0x00000100ff000001, 0x00000100ff000100, 0x00000100ff010000, + 0x0000010000ffff00, 0x0000010000ff00ff, 0x0000010000ff0000, 0x0000010000ff0001, + 0x0000010000ff0100, 0x000001000000ffff, 0x000001000000ff00, 0x000001000000ff01, + 0x00000100000000ff, 0x0000010000000000, 0x0000010000000001, 0x00000100000001ff, + 0x0000010000000100, 0x0000010000000101, 0x000001000001ff00, 0x00000100000100ff, + 0x0000010000010000, 0x0000010000010001, 0x0000010000010100, 0x0000010001ffff00, + 0x0000010001ff0000, 0x0000010001ff0100, 0x000001000100ff00, 0x00000100010000ff, + 0x0000010001000000, 0x0000010001000001, 0x00000100010001ff, 0x0000010001000100, + 0x0000010001010000, 0x00000101ffff00ff, 0x00000101ffff01ff, 0x00000101ff000000, + 0x00000101ff000101, 0x00000101ff01ffff, 0x00000101ff010000, 0x00000101ff010001, + 0x00000101ff010100, 0x0000010100ff0000, 0x0000010100ff01ff, 0x0000010100ff0100, + 0x000001010000ff00, 0x0000010100000000, 0x0000010100000001, 0x00000101000001ff, + 0x0000010100000100, 0x000001010001ff01, 0x0000010100010000, 0x00000101000101ff, + 0x0000010100010101, 0x0000010101ffff00, 0x0000010101ff0101, 0x000001010100ff01, + 0x0000010101000000, 0x0000010101000001, 0x00000101010001ff, 0x0000010101000101, + 0x000001010101ff00, 0x0001ffffffff0000, 0x0001ffffff0000ff, 0x0001ffffff000001, + 0x0001ffffff000100, 0x0001ffffff010000, 0x0001ffff00ff00ff, 0x0001ffff0000ffff, + 0x0001ffff00000000, 0x0001ffff00000001, 0x0001ffff000001ff, 0x0001ffff00000101, + 0x0001ffff0001ff00, 0x0001ffff000100ff, 0x0001ffff00010001, 0x0001ffff00010100, + 0x0001ffff01ffff00, 0x0001ffff01000001, 0x0001ffff01010000, 0x0001ff00ffffff00, + 0x0001ff00ffff00ff, 0x0001ff00ffff0001, 0x0001ff00ffff0100, 0x0001ff00ff00ff01, + 0x0001ff00ff000000, 0x0001ff00ff01ff00, 0x0001ff00ff01ff01, 0x0001ff00ff010001, + 0x0001ff00ff010100, 0x0001ff0000ff0000, 0x0001ff0000ff0100, 0x0001ff000000ff00, + 0x0001ff0000000000, 0x0001ff0000000001, 0x0001ff0000000100, 0x0001ff0000010000, + 0x0001ff0000010001, 0x0001ff0000010101, 0x0001ff0001ff00ff, 0x0001ff0001ff0101, + 0x0001ff000100ff01, 0x0001ff0001000000, 0x0001ff000101ff00, 0x0001ff0001010001, + 0x0001ff0001010100, 0x0001ff01ff00ff00, 0x0001ff01ff000001, 0x0001ff01ff000100, + 0x0001ff0100ffffff, 0x0001ff0100ffff00, 0x0001ff0100ff0001, 0x0001ff0100000000, + 0x0001ff0100000001, 0x0001ff01000001ff, 0x0001ff010001ffff, 0x0001ff0101ff0000, + 0x0001ff010100ff00, 0x0001ff0101000001, 0x0001ff0101010000, 0x000100ffff00ff00, + 0x000100ffff00ff01, 0x000100ffff000000, 0x000100ffff000001, 0x000100ffff000101, + 0x000100ffff01ff00, 0x000100ffff010001, 0x000100ffff010100, 0x000100ff00ffffff, + 0x000100ff00ffff01, 0x000100ff00ff0000, 0x000100ff00ff01ff, 0x000100ff00ff0101, + 0x000100ff0000ff00, 0x000100ff000000ff, 0x000100ff00000000, 0x000100ff00000001, + 0x000100ff00000100, 0x000100ff00000101, 0x000100ff0001ffff, 0x000100ff0001ff01, + 0x000100ff00010000, 0x000100ff01ff00ff, 0x000100ff01ff0000, 0x000100ff01ff0100, + 0x000100ff0100ffff, 0x000100ff0100ff01, 0x000100ff010000ff, 0x000100ff01000000, + 0x000100ff01000001, 0x000100ff010001ff, 0x000100ff01000101, 0x000100ff0101ff00, + 0x000100ff010100ff, 0x000100ff01010100, 0x00010000ffff0000, 0x00010000ffff01ff, + 0x00010000ffff0101, 0x00010000ff00ff00, 0x00010000ff000000, 0x00010000ff000001, + 0x00010000ff000100, 0x0001000000ff00ff, 0x0001000000ff0000, 0x0001000000ff0001, + 0x0001000000ff0100, 0x000100000000ffff, 0x000100000000ff00, 0x00010000000000ff, + 0x0001000000000000, 0x0001000000000001, 0x0001000000000100, 0x000100000001ff00, + 0x00010000000100ff, 0x0001000000010000, 0x0001000000010001, 0x0001000000010100, + 0x0001000001ff0001, 0x0001000001ff0100, 0x0001000001ff0101, 0x000100000100ff00, + 0x0001000001000000, 0x0001000001000001, 0x0001000001000100, 0x0001000001000101, + 0x000100000101ff01, 0x0001000001010000, 0x0001000001010001, 0x00010000010101ff, + 0x00010001ffffff01, 0x00010001ffff0100, 0x00010001ff000000, 0x00010001ff01ffff, + 0x00010001ff010001, 0x00010001ff0101ff, 0x00010001ff010100, 0x0001000100ffffff, + 0x0001000100ff0000, 0x0001000100ff01ff, 0x0001000100ff0101, 0x000100010000ff00, + 0x00010001000000ff, 0x0001000100000000, 0x0001000100000001, 0x00010001000001ff, + 0x0001000100000101, 0x000100010001ffff, 0x0001000100010000, 0x00010001000101ff, + 0x0001000101ffffff, 0x0001000101ffff01, 0x0001000101ff0000, 0x0001000101ff0101, + 0x00010001010000ff, 0x0001000101000001, 0x00010001010001ff, 0x0001000101000100, + 0x000100010101ffff, 0x00010001010100ff, 0x0001000101010001, 0x0001000101010101, + 0x000101ffff000001, 0x000101ffff000100, 0x000101ffff010000, 0x000101ff00ffff00, + 0x000101ff0000ff01, 0x000101ff00000000, 0x000101ff00000101, 0x000101ff0001ff00, + 0x000101ff00010100, 0x000101ff01ff0000, 0x000101ff0100ff00, 0x000101ff010001ff, + 0x000101ff01010001, 0x00010100ffffff00, 0x00010100ffff00ff, 0x00010100ff00ffff, + 0x00010100ff000000, 0x00010100ff01ff00, 0x00010100ff0100ff, 0x00010100ff010001, + 0x00010100ff010100, 0x0001010000ffffff, 0x0001010000ffff00, 0x0001010000ff0000, + 0x0001010000ff0001, 0x0001010000ff01ff, 0x000101000000ff00, 0x00010100000000ff, + 0x0001010000000000, 0x0001010000000001, 0x0001010000000100, 0x000101000001ffff, + 0x0001010000010000, 0x0001010000010101, 0x0001010001ffff01, 0x0001010001ff00ff, + 0x0001010001ff0101, 0x0001010001000000, 0x000101000101ff00, 0x00010100010100ff, + 0x0001010001010000, 0x0001010001010100, 0x00010101ff00ff00, 0x00010101ff000001, + 0x00010101ff0001ff, 0x0001010100ffff00, 0x0001010100ff00ff, 0x0001010100ff0100, + 0x000101010000ffff, 0x0001010100000000, 0x00010101000001ff, 0x0001010100000101, + 0x00010101000100ff, 0x0001010100010000, 0x0001010100010100, 0x0001010101ff0001, + 0x00010101010000ff, 0x00010101010001ff, 0x0001010101000101, 0x0001010101010001, + 0x01ffffffffffffff, 0x01ffffffffffff01, 0x01ffffffffff01ff, 0x01ffffffffff0101, + 0x01ffffffff01ffff, 0x01ffffffff01ff01, 0x01ffffffff0101ff, 0x01ffffffff010101, + 0x01ffffff00ff0000, 0x01ffffff0000ffff, 0x01ffffff0000ff00, 0x01ffffff000000ff, + 0x01ffffff00000001, 0x01ffffff00000100, 0x01ffffff00010000, 0x01ffffff01ffffff, + 0x01ffffff01ffff01, 0x01ffffff01ff01ff, 0x01ffffff01ff0101, 0x01ffffff01000000, + 0x01ffffff0101ffff, 0x01ffffff0101ff01, 0x01ffffff010101ff, 0x01ffffff01010101, + 0x01ffff00ffff0000, 0x01ffff00ff00ff00, 0x01ffff00ff0000ff, 0x01ffff00ff000001, + 0x01ffff00ff000100, 0x01ffff00ff010000, 0x01ffff0000ffff00, 0x01ffff0000ff00ff, + 0x01ffff0000ff0100, 0x01ffff000000ffff, 0x01ffff000000ff01, 0x01ffff0000000000, + 0x01ffff0000000001, 0x01ffff00000001ff, 0x01ffff0000000100, 0x01ffff00000100ff, + 0x01ffff0000010001, 0x01ffff0000010100, 0x01ffff0001ff0000, 0x01ffff0001ff0100, + 0x01ffff00010000ff, 0x01ffff0001000001, 0x01ffff0001000100, 0x01ffff0001010000, + 0x01ffff01ffffffff, 0x01ffff01ffffff01, 0x01ffff01ffff01ff, 0x01ffff01ffff0101, + 0x01ffff01ff000000, 0x01ffff01ff01ffff, 0x01ffff01ff01ff01, 0x01ffff01ff0101ff, + 0x01ffff01ff010101, 0x01ffff010000ff00, 0x01ffff01000000ff, 0x01ffff0100000100, + 0x01ffff0100010000, 0x01ffff0101ffffff, 0x01ffff0101ffff01, 0x01ffff0101ff01ff, + 0x01ffff0101ff0101, 0x01ffff0101000000, 0x01ffff010101ffff, 0x01ffff010101ff01, + 0x01ffff01010101ff, 0x01ffff0101010101, 0x01ff00ffff0000ff, 0x01ff00ffff000100, + 0x01ff00ff00ffff00, 0x01ff00ff00ff00ff, 0x01ff00ff0000ff00, 0x01ff00ff00000000, + 0x01ff00ff00000101, 0x01ff00ff0001ff00, 0x01ff00ff000100ff, 0x01ff00ff00010100, + 0x01ff00ff010000ff, 0x01ff00ff01000100, 0x01ff0000ffffff00, 0x01ff0000ffff0100, + 0x01ff0000ff00ff01, 0x01ff0000ff000000, 0x01ff0000ff000101, 0x01ff0000ff010001, + 0x01ff0000ff010100, 0x01ff000000ffffff, 0x01ff000000ffff00, 0x01ff000000ff0000, + 0x01ff000000ff01ff, 0x01ff00000000ff00, 0x01ff0000000000ff, 0x01ff000000000000, + 0x01ff000000000001, 0x01ff000000000100, 0x01ff000000000101, 0x01ff000000010000, + 0x01ff000000010001, 0x01ff0000000101ff, 0x01ff000000010101, 0x01ff000001ffff00, + 0x01ff000001ff00ff, 0x01ff000001ff0001, 0x01ff000001ff0100, 0x01ff00000100ffff, + 0x01ff00000100ff01, 0x01ff000001000000, 0x01ff0000010001ff, 0x01ff000001010001, + 0x01ff0001ff00ff00, 0x01ff0001ff000001, 0x01ff0001ff000100, 0x01ff0001ff010000, + 0x01ff000100ffff00, 0x01ff000100ff00ff, 0x01ff000100ff0100, 0x01ff000100ff0101, + 0x01ff00010000ffff, 0x01ff000100000000, 0x01ff000100000100, 0x01ff000100000101, + 0x01ff00010001ff00, 0x01ff000100010001, 0x01ff000100010101, 0x01ff000101ff0000, + 0x01ff00010100ff00, 0x01ff000101000101, 0x01ff0001010100ff, 0x01ff01ffffffffff, + 0x01ff01ffffffff01, 0x01ff01ffffff01ff, 0x01ff01ffffff0101, 0x01ff01ffff000000, + 0x01ff01ffff01ffff, 0x01ff01ffff01ff01, 0x01ff01ffff0101ff, 0x01ff01ffff010101, + 0x01ff01ff00ffff00, 0x01ff01ff00ff0000, 0x01ff01ff0000ff00, 0x01ff01ff000000ff, + 0x01ff01ff00000100, 0x01ff01ff00010000, 0x01ff01ff00010100, 0x01ff01ff01ffffff, + 0x01ff01ff01ffff01, 0x01ff01ff01ff01ff, 0x01ff01ff01ff0101, 0x01ff01ff01000000, + 0x01ff01ff0101ffff, 0x01ff01ff0101ff01, 0x01ff01ff010101ff, 0x01ff01ff01010101, + 0x01ff0100ffff0000, 0x01ff0100ffff0001, 0x01ff0100ff00ff00, 0x01ff0100ff0000ff, + 0x01ff0100ff000001, 0x01ff0100ff010000, 0x01ff010000ffff00, 0x01ff010000ff00ff, + 0x01ff010000ff0001, 0x01ff010000ff0100, 0x01ff01000000ffff, 0x01ff01000000ff01, + 0x01ff010000000000, 0x01ff010000000101, 0x01ff01000001ff00, 0x01ff0100000100ff, + 0x01ff010001ff0000, 0x01ff010001000001, 0x01ff010001000100, 0x01ff010001010000, + 0x01ff0101ffffffff, 0x01ff0101ffffff01, 0x01ff0101ffff01ff, 0x01ff0101ffff0101, + 0x01ff0101ff000000, 0x01ff0101ff01ffff, 0x01ff0101ff01ff01, 0x01ff0101ff0101ff, + 0x01ff0101ff010101, 0x01ff010100ff0000, 0x01ff01010000ff00, 0x01ff0101000000ff, + 0x01ff010100000001, 0x01ff010101ffffff, 0x01ff010101ffff01, 0x01ff010101ff01ff, + 0x01ff010101ff0101, 0x01ff010101000000, 0x01ff01010101ffff, 0x01ff01010101ff01, + 0x01ff0101010101ff, 0x01ff010101010101, 0x0100ffffffff0000, 0x0100ffffff00ff00, + 0x0100ffffff000001, 0x0100ffffff0001ff, 0x0100ffffff000100, 0x0100ffffff010000, + 0x0100ffff00ffff00, 0x0100ffff00ff0001, 0x0100ffff00ff0100, 0x0100ffff00000000, + 0x0100ffff000001ff, 0x0100ffff00000101, 0x0100ffff00010100, 0x0100ffff00010101, + 0x0100ffff01ff0000, 0x0100ffff0100ff00, 0x0100ffff010000ff, 0x0100ffff01000001, + 0x0100ffff01000100, 0x0100ffff01010000, 0x0100ff00ffffff00, 0x0100ff00ffff00ff, + 0x0100ff00ffff0001, 0x0100ff00ffff0100, 0x0100ff00ff00ffff, 0x0100ff00ff000000, + 0x0100ff00ff0001ff, 0x0100ff00ff000101, 0x0100ff00ff01ff00, 0x0100ff00ff0100ff, + 0x0100ff00ff010001, 0x0100ff00ff010100, 0x0100ff0000ffffff, 0x0100ff0000ff0000, + 0x0100ff000000ffff, 0x0100ff000000ff00, 0x0100ff00000000ff, 0x0100ff0000000000, + 0x0100ff0000000001, 0x0100ff0000000100, 0x0100ff000001ff01, 0x0100ff0000010000, + 0x0100ff0001ff00ff, 0x0100ff0001ff0001, 0x0100ff000100ff01, 0x0100ff0001000000, + 0x0100ff00010001ff, 0x0100ff000101ff00, 0x0100ff00010100ff, 0x0100ff0001010001, + 0x0100ff0001010100, 0x0100ff01ffff0000, 0x0100ff01ff00ff00, 0x0100ff01ff0000ff, + 0x0100ff01ff000100, 0x0100ff01ff010000, 0x0100ff0100ff00ff, 0x0100ff0100ff0001, + 0x0100ff0100ff0100, 0x0100ff010000ffff, 0x0100ff010000ff01, 0x0100ff0100000000, + 0x0100ff01000001ff, 0x0100ff0100010001, 0x0100ff0100010100, 0x0100ff0101ff0000, + 0x0100ff01010000ff, 0x0100ff0101000001, 0x0100ff0101010100, 0x010000ffffffff00, + 0x010000ffffff00ff, 0x010000ffffff0001, 0x010000ffff00ffff, 0x010000ffff000000, + 0x010000ffff0001ff, 0x010000ffff010001, 0x010000ff00ffffff, 0x010000ff00ff0101, + 0x010000ff0000ff00, 0x010000ff000000ff, 0x010000ff00000000, 0x010000ff00000001, + 0x010000ff000001ff, 0x010000ff00000100, 0x010000ff0001ffff, 0x010000ff0001ff00, + 0x010000ff0001ff01, 0x010000ff00010000, 0x010000ff01ff00ff, 0x010000ff01ff0001, + 0x010000ff0100ff01, 0x010000ff010000ff, 0x010000ff01000000, 0x010000ff010001ff, + 0x010000ff0101ff00, 0x010000ff01010100, 0x01000000ffffffff, 0x01000000ffff0000, + 0x01000000ffff01ff, 0x01000000ffff0101, 0x01000000ff00ffff, 0x01000000ff00ff00, + 0x01000000ff0000ff, 0x01000000ff000000, 0x01000000ff000001, 0x01000000ff000100, + 0x01000000ff01ff00, 0x01000000ff010000, 0x01000000ff010100, 0x01000000ff010101, + 0x0100000000ffff00, 0x0100000000ff00ff, 0x0100000000ff0000, 0x0100000000ff0001, + 0x0100000000ff0100, 0x010000000000ffff, 0x010000000000ff00, 0x010000000000ff01, + 0x01000000000000ff, 0x0100000000000000, 0x0100000000000001, 0x01000000000001ff, + 0x0100000000000100, 0x0100000000000101, 0x010000000001ff00, 0x01000000000100ff, + 0x0100000000010000, 0x0100000000010001, 0x0100000000010100, 0x0100000001ffff00, + 0x0100000001ff0000, 0x0100000001ff01ff, 0x010000000100ff00, 0x010000000100ff01, + 0x01000000010000ff, 0x0100000001000000, 0x0100000001000001, 0x0100000001000100, + 0x0100000001000101, 0x010000000101ffff, 0x010000000101ff01, 0x0100000001010000, + 0x01000000010101ff, 0x0100000001010101, 0x01000001ffffff00, 0x01000001ffff00ff, + 0x01000001ff00ffff, 0x01000001ff000000, 0x01000001ff000100, 0x01000001ff01ffff, + 0x01000001ff010001, 0x01000001ff010100, 0x0100000100ff0000, 0x0100000100ff01ff, + 0x0100000100ff0100, 0x010000010000ff00, 0x010000010000ff01, 0x0100000100000000, + 0x0100000100000001, 0x0100000100000100, 0x0100000100010000, 0x01000001000101ff, + 0x0100000101ffff01, 0x0100000101ff00ff, 0x0100000101ff0100, 0x0100000101ff0101, + 0x010000010100ff01, 0x01000001010000ff, 0x0100000101000000, 0x01000001010100ff, + 0x0100000101010001, 0x0100000101010100, 0x010001ffffff0000, 0x010001ffff000001, + 0x010001ffff000100, 0x010001ffff010000, 0x010001ff00ffff00, 0x010001ff00ff0001, + 0x010001ff0000ffff, 0x010001ff0000ff01, 0x010001ff00000000, 0x010001ff00000001, + 0x010001ff00000101, 0x010001ff000100ff, 0x010001ff00010000, 0x010001ff01ff0000, + 0x010001ff0100ff00, 0x010001ff01000001, 0x010001ff01000100, 0x010001ff01010000, + 0x01000100ffff00ff, 0x01000100ffff0001, 0x01000100ffff0100, 0x01000100ff00ffff, + 0x01000100ff00ff01, 0x01000100ff000000, 0x01000100ff0001ff, 0x01000100ff000101, + 0x01000100ff01ffff, 0x01000100ff01ff00, 0x01000100ff0100ff, 0x01000100ff010001, + 0x0100010000ffffff, 0x0100010000ffff01, 0x0100010000ff0000, 0x0100010000ff01ff, + 0x0100010000ff0101, 0x010001000000ff00, 0x01000100000000ff, 0x0100010000000000, + 0x0100010000000001, 0x0100010000000100, 0x010001000001ff01, 0x0100010000010000, + 0x0100010000010001, 0x0100010000010101, 0x0100010001ffff00, 0x0100010001ff00ff, + 0x010001000100ffff, 0x010001000100ff01, 0x0100010001000000, 0x0100010001000101, + 0x010001000101ff00, 0x0100010001010001, 0x01000101ffff0000, 0x01000101ff000000, + 0x01000101ff010000, 0x0100010100ff00ff, 0x0100010100ff0001, 0x0100010100ff0100, + 0x010001010000ffff, 0x0100010100000000, 0x01000101000001ff, 0x010001010001ff00, + 0x0100010101ff0000, 0x010001010100ff00, 0x01000101010000ff, 0x0100010101000000, + 0x0100010101000001, 0x0101ffffffffffff, 0x0101ffffffffff01, 0x0101ffffffff01ff, + 0x0101ffffffff0101, 0x0101ffffff000000, 0x0101ffffff01ffff, 0x0101ffffff01ff01, + 0x0101ffffff0101ff, 0x0101ffffff010101, 0x0101ffff00ff0000, 0x0101ffff0000ff00, + 0x0101ffff000000ff, 0x0101ffff00000001, 0x0101ffff00000100, 0x0101ffff01ffffff, + 0x0101ffff01ffff01, 0x0101ffff01ff01ff, 0x0101ffff01ff0101, 0x0101ffff01000000, + 0x0101ffff0101ffff, 0x0101ffff0101ff01, 0x0101ffff010101ff, 0x0101ffff01010101, + 0x0101ff00ffff0000, 0x0101ff00ffff0100, 0x0101ff00ff00ff00, 0x0101ff00ff0000ff, + 0x0101ff00ff000001, 0x0101ff00ff000100, 0x0101ff00ff000101, 0x0101ff0000ff0001, + 0x0101ff0000ff0100, 0x0101ff000000ff00, 0x0101ff0000000000, 0x0101ff00000001ff, + 0x0101ff0000000101, 0x0101ff000001ff00, 0x0101ff00000100ff, 0x0101ff0001ff0000, + 0x0101ff000100ffff, 0x0101ff000100ff01, 0x0101ff0001000001, 0x0101ff0001000100, + 0x0101ff01ffffff01, 0x0101ff01ffff01ff, 0x0101ff01ffff0101, 0x0101ff01ff00ffff, + 0x0101ff01ff000100, 0x0101ff01ff01ff01, 0x0101ff01ff0101ff, 0x0101ff01ff010101, + 0x0101ff0100ff0000, 0x0101ff010000ff00, 0x0101ff0100000001, 0x0101ff0100000100, + 0x0101ff0100010000, 0x0101ff0101ffffff, 0x0101ff0101ffff01, 0x0101ff0101ff01ff, + 0x0101ff0101ff0101, 0x0101ff0101000000, 0x0101ff010101ffff, 0x0101ff010101ff01, + 0x0101ff01010101ff, 0x0101ff0101010101, 0x010100ffff000100, 0x010100ffff010000, + 0x010100ff00ffff00, 0x010100ff00ff00ff, 0x010100ff0000ffff, 0x010100ff000000ff, + 0x010100ff00000000, 0x010100ff000001ff, 0x010100ff00000101, 0x010100ff0001ff00, + 0x010100ff00010000, 0x010100ff00010001, 0x010100ff000101ff, 0x010100ff00010100, + 0x010100ff01ff0000, 0x01010000ffff0001, 0x01010000ffff0100, 0x01010000ff00ffff, + 0x01010000ff00ff01, 0x01010000ff000000, 0x01010000ff0001ff, 0x01010000ff010001, + 0x01010000ff010100, 0x0101000000ffff01, 0x0101000000ff0000, 0x010100000000ff00, + 0x01010000000000ff, 0x0101000000000000, 0x0101000000000001, 0x0101000000000100, + 0x0101000000010000, 0x0101000000010101, 0x0101000001ffff00, 0x0101000001ff00ff, + 0x0101000001ff0000, 0x0101000001ff0001, 0x0101000001ff0100, 0x010100000100ff01, + 0x0101000001000000, 0x01010000010001ff, 0x01010001ffff0000, 0x01010001ff00ff00, + 0x01010001ff000001, 0x01010001ff000101, 0x01010001ff01ff00, 0x01010001ff010000, + 0x0101000100ff00ff, 0x0101000100ff0001, 0x0101000100ff0101, 0x010100010000ff01, + 0x0101000100000000, 0x0101000100000001, 0x01010001000001ff, 0x010100010001ffff, + 0x010100010001ff01, 0x0101000101ff0001, 0x010100010100ffff, 0x0101000101000000, + 0x0101000101000001, 0x0101000101000100, 0x010100010101ff00, 0x01010001010100ff, + 0x0101000101010001, 0x010101ffffffffff, 0x010101ffffffff01, 0x010101ffffff01ff, + 0x010101ffffff0101, 0x010101ffff01ffff, 0x010101ffff01ff01, 0x010101ffff0101ff, + 0x010101ffff010101, 0x010101ff0000ff00, 0x010101ff000000ff, 0x010101ff00000001, + 0x010101ff00000100, 0x010101ff01ffffff, 0x010101ff01ffff01, 0x010101ff01ff01ff, + 0x010101ff01ff0101, 0x010101ff01000000, 0x010101ff0101ffff, 0x010101ff0101ff01, + 0x010101ff010101ff, 0x010101ff01010101, 0x01010100ffff0000, 0x01010100ff0000ff, + 0x01010100ff000100, 0x01010100ff01ff00, 0x01010100ff010000, 0x0101010000ffff00, + 0x010101000000ffff, 0x0101010000000000, 0x0101010000000101, 0x010101000001ff00, + 0x0101010000010001, 0x0101010000010100, 0x010101000100ffff, 0x0101010001000001, + 0x01010101ffffffff, 0x01010101ffffff01, 0x01010101ffff01ff, 0x01010101ffff0101, + 0x01010101ff01ffff, 0x01010101ff01ff01, 0x01010101ff0101ff, 0x01010101ff010101, + 0x010101010000ff00, 0x01010101000000ff, 0x0101010100000001, 0x0101010101ffffff, + 0x0101010101ffff01, 0x0101010101ff01ff, 0x0101010101ff0101, 0x0101010101000000, + 0x010101010101ffff, 0x010101010101ff01, 0x01010101010101ff, 0x0101010101010101, +GGML_TABLE_END() +#else +GGML_TABLE_BEGIN(uint32_t, iq1s_grid_gpu, NGRID_IQ1S) + 0x00000000, 0x00000002, 0x00000101, 0x00000200, 0x00000202, 0x00010001, 0x00010101, 0x00020000, + 0x00020002, 0x00020200, 0x00020202, 0x01000101, 0x01010001, 0x01010100, 0x01010102, 0x01020101, + 0x02000000, 0x02000002, 0x02000200, 0x02000202, 0x02010101, 0x02020000, 0x02020002, 0x02020200, + 0x02020202, 0x00000110, 0x00000111, 0x00010011, 0x00010110, 0x00010112, 0x00010211, 0x00010212, + 0x00020111, 0x01000011, 0x01000112, 0x01000211, 0x01010012, 0x01010111, 0x01010212, 0x01020011, + 0x01020110, 0x01020112, 0x01020210, 0x02000111, 0x02010011, 0x02010110, 0x02010112, 0x02020111, + 0x00000020, 0x00000022, 0x00000220, 0x00000222, 0x00010121, 0x00020020, 0x00020022, 0x00020220, + 0x00020222, 0x01000121, 0x01010021, 0x01010221, 0x01020120, 0x01020221, 0x02000020, 0x02000022, + 0x02000220, 0x02000222, 0x02010021, 0x02010121, 0x02010221, 0x02020020, 0x02020022, 0x02020220, + 0x02020222, 0x00011001, 0x00011100, 0x00011102, 0x00021101, 0x01001001, 0x01001201, 0x01011101, + 0x01011202, 0x01021100, 0x01021101, 0x02011001, 0x02011201, 0x02021101, 0x00001011, 0x00001110, + 0x00001111, 0x00001112, 0x00011111, 0x00011210, 0x00011212, 0x00021211, 0x01001010, 0x01001111, + 0x01001212, 0x01011010, 0x01011011, 0x01011110, 0x01011111, 0x01011112, 0x01011211, 0x01021010, + 0x01021012, 0x01021111, 0x01021210, 0x01021212, 0x02001011, 0x02011011, 0x02011111, 0x02011210, + 0x02011212, 0x02021011, 0x02021110, 0x02021111, 0x02021112, 0x02021211, 0x00011120, 0x00011221, + 0x01001021, 0x01001120, 0x01011020, 0x01011022, 0x01011121, 0x01011220, 0x01021020, 0x01021021, + 0x01021122, 0x01021221, 0x02001121, 0x02011021, 0x02011120, 0x02011221, 0x00002000, 0x00002002, + 0x00002200, 0x00002202, 0x00012101, 0x00022000, 0x00022002, 0x00022200, 0x00022202, 0x01002101, + 0x01012001, 0x01012102, 0x01022101, 0x02002000, 0x02002002, 0x02002200, 0x02002202, 0x02012101, + 0x02022000, 0x02022002, 0x02022200, 0x02022202, 0x00002111, 0x00012011, 0x00012110, 0x00012211, + 0x00022110, 0x00022111, 0x01002011, 0x01012010, 0x01012011, 0x01012111, 0x01022011, 0x01022110, + 0x01022211, 0x02012011, 0x02012110, 0x02012112, 0x02012211, 0x02022111, 0x00002020, 0x00002022, + 0x00002220, 0x00002222, 0x00012121, 0x00022020, 0x00022022, 0x00022220, 0x00022222, 0x01002121, + 0x01012021, 0x01012221, 0x01022021, 0x01022121, 0x02002020, 0x02002022, 0x02002121, 0x02002220, + 0x02002222, 0x02012121, 0x02022020, 0x02022022, 0x02022220, 0x02022222, 0x00110000, 0x00110001, + 0x00110100, 0x00110201, 0x00120100, 0x00120101, 0x01100001, 0x01100100, 0x01110000, 0x01110101, + 0x01110200, 0x01120001, 0x01120100, 0x01120101, 0x01120201, 0x02110001, 0x02110100, 0x02110102, + 0x02120001, 0x02120101, 0x00100011, 0x00100110, 0x00100112, 0x00100211, 0x00110010, 0x00110012, + 0x00110111, 0x00110210, 0x00120011, 0x00120110, 0x00120211, 0x01100111, 0x01100212, 0x01110010, + 0x01110011, 0x01110012, 0x01110110, 0x01110111, 0x01110112, 0x01110211, 0x01120010, 0x01120111, + 0x02100110, 0x02110012, 0x02110111, 0x02120011, 0x02120110, 0x00110021, 0x00110120, 0x00110122, + 0x00120121, 0x01100020, 0x01100122, 0x01100221, 0x01110022, 0x01110121, 0x01110220, 0x01110222, + 0x01120120, 0x01120122, 0x02100121, 0x02110021, 0x02110120, 0x02110122, 0x02120121, 0x00101001, + 0x00101102, 0x00101201, 0x00111100, 0x00111101, 0x00111200, 0x00111201, 0x00121001, 0x00121102, + 0x01101001, 0x01101101, 0x01101102, 0x01101200, 0x01101202, 0x01111001, 0x01111100, 0x01111101, + 0x01111102, 0x01111201, 0x01121002, 0x01121101, 0x01121200, 0x02101100, 0x02101201, 0x02111000, + 0x02111100, 0x02111101, 0x02111200, 0x02111201, 0x02111202, 0x02121001, 0x02121100, 0x02121101, + 0x02121201, 0x00101012, 0x00101111, 0x00101212, 0x00111011, 0x00111110, 0x00111111, 0x00111112, + 0x00111211, 0x00121010, 0x00121012, 0x00121111, 0x00121210, 0x00121212, 0x01101011, 0x01101110, + 0x01101111, 0x01101112, 0x01111011, 0x01111012, 0x01111110, 0x01111111, 0x01111112, 0x01111211, + 0x01111212, 0x01121011, 0x01121110, 0x01121111, 0x01121112, 0x01121211, 0x02101010, 0x02101012, + 0x02101110, 0x02101111, 0x02101210, 0x02101212, 0x02111010, 0x02111011, 0x02111110, 0x02111111, + 0x02111112, 0x02111211, 0x02111212, 0x02121010, 0x02121012, 0x02121111, 0x00101021, 0x00101120, + 0x00101121, 0x00101122, 0x00111121, 0x00111122, 0x00111220, 0x00111222, 0x00121021, 0x00121122, + 0x01101020, 0x01101022, 0x01101120, 0x01101121, 0x01101220, 0x01101222, 0x01111021, 0x01111121, + 0x01111122, 0x01111220, 0x01111221, 0x01121021, 0x01121120, 0x01121121, 0x01121220, 0x01121221, + 0x01121222, 0x02101122, 0x02101222, 0x02111022, 0x02111121, 0x02121120, 0x02121221, 0x00112001, + 0x00112102, 0x00122101, 0x01102001, 0x01102100, 0x01102102, 0x01102201, 0x01112000, 0x01112101, + 0x01112200, 0x01112202, 0x01122000, 0x01122001, 0x01122100, 0x01122102, 0x01122201, 0x02102101, + 0x02112001, 0x02112100, 0x02122101, 0x00112010, 0x00112012, 0x00112111, 0x00112212, 0x00122011, + 0x00122111, 0x01102012, 0x01102110, 0x01102111, 0x01102210, 0x01112011, 0x01112110, 0x01112111, + 0x01112112, 0x01112211, 0x01112212, 0x01122010, 0x01122111, 0x01122212, 0x02102211, 0x02112011, + 0x02112012, 0x02112111, 0x02112210, 0x02122011, 0x02122112, 0x02122211, 0x00102221, 0x00112122, + 0x00122120, 0x00122122, 0x01102120, 0x01102122, 0x01102221, 0x01112020, 0x01112022, 0x01112121, + 0x01112220, 0x01122021, 0x01122122, 0x01122221, 0x02102121, 0x02112021, 0x02112122, 0x02112222, + 0x00200000, 0x00200002, 0x00200200, 0x00200202, 0x00210101, 0x00220000, 0x00220002, 0x00220101, + 0x00220200, 0x00220202, 0x01200101, 0x01210001, 0x01210201, 0x01220001, 0x01220101, 0x02200000, + 0x02200002, 0x02200200, 0x02200202, 0x02210101, 0x02220000, 0x02220002, 0x02220101, 0x02220200, + 0x02220202, 0x00200111, 0x00210011, 0x00210110, 0x00210211, 0x00220111, 0x01200012, 0x01200110, + 0x01200211, 0x01210111, 0x01210210, 0x01210212, 0x01220011, 0x01220110, 0x01220111, 0x01220112, + 0x02200111, 0x02210010, 0x02210112, 0x02210211, 0x02220111, 0x00200021, 0x00200220, 0x00200222, + 0x00210021, 0x00210121, 0x00220020, 0x00220022, 0x00220220, 0x00220222, 0x01200121, 0x01210021, + 0x01210122, 0x01210221, 0x01220121, 0x02200021, 0x02200220, 0x02200222, 0x02210021, 0x02210121, + 0x02220020, 0x02220022, 0x02220220, 0x02220222, 0x00201101, 0x00211100, 0x00211102, 0x00211201, + 0x00221101, 0x01201100, 0x01201101, 0x01201102, 0x01201201, 0x01211002, 0x01211101, 0x01211200, + 0x01211202, 0x01221102, 0x02201101, 0x02211001, 0x02211100, 0x02211201, 0x02221001, 0x02221101, + 0x00201211, 0x00211111, 0x00221011, 0x00221211, 0x01201010, 0x01201111, 0x01201210, 0x01211011, + 0x01211110, 0x01211111, 0x01211211, 0x01221012, 0x01221111, 0x01221210, 0x02201211, 0x02211010, + 0x02211110, 0x02211111, 0x02211210, 0x02211212, 0x02221011, 0x02221110, 0x02221112, 0x02221211, + 0x00201121, 0x00211020, 0x00211022, 0x00211221, 0x00221121, 0x01201021, 0x01201221, 0x01211121, + 0x01221020, 0x01221021, 0x01221221, 0x02201120, 0x02201122, 0x02211020, 0x02211222, 0x00202000, + 0x00202002, 0x00202200, 0x00202202, 0x00212101, 0x00222000, 0x00222002, 0x00222200, 0x00222202, + 0x01202101, 0x01212001, 0x01212100, 0x01222101, 0x02202000, 0x02202002, 0x02202200, 0x02202202, + 0x02222000, 0x02222002, 0x02222200, 0x02222202, 0x00202211, 0x00212011, 0x00212110, 0x00212211, + 0x00222111, 0x01202112, 0x01202211, 0x01212012, 0x01212111, 0x01222011, 0x01222110, 0x01222112, + 0x01222211, 0x02202111, 0x02212010, 0x02212112, 0x02212211, 0x02222110, 0x02222111, 0x00202020, + 0x00202022, 0x00202220, 0x00202222, 0x00222020, 0x00222022, 0x00222220, 0x00222222, 0x01202121, + 0x01212021, 0x01212122, 0x01212221, 0x01222121, 0x02202020, 0x02202022, 0x02202220, 0x02202222, + 0x02212121, 0x02222020, 0x02222022, 0x02222220, 0x02222222, 0x10000101, 0x10010001, 0x10010102, + 0x10020101, 0x11000201, 0x11010002, 0x11010101, 0x11010200, 0x11010202, 0x11020001, 0x11020100, + 0x11020102, 0x12010100, 0x12010201, 0x12020001, 0x12020102, 0x10000010, 0x10000011, 0x10000110, + 0x10000112, 0x10000211, 0x10010012, 0x10010111, 0x10010112, 0x10010210, 0x10010212, 0x10020011, + 0x10020112, 0x10020211, 0x11000111, 0x11000210, 0x11000212, 0x11010011, 0x11010110, 0x11010111, + 0x11010112, 0x11010211, 0x11010212, 0x11020111, 0x11020210, 0x11020212, 0x12000011, 0x12000110, + 0x12000112, 0x12010010, 0x12010012, 0x12010111, 0x12020010, 0x12020011, 0x12020012, 0x10000121, + 0x10010021, 0x10010120, 0x10010122, 0x10020121, 0x11000021, 0x11010022, 0x11010121, 0x11010222, + 0x11020120, 0x11020221, 0x12000221, 0x12010120, 0x12020121, 0x10001001, 0x10011101, 0x10011201, + 0x10021201, 0x11001101, 0x11001200, 0x11001202, 0x11011001, 0x11011100, 0x11011101, 0x11011102, + 0x11021001, 0x11021002, 0x11021101, 0x11021200, 0x11021202, 0x12001001, 0x12001102, 0x12001201, + 0x12011000, 0x12011002, 0x12011101, 0x12021000, 0x12021001, 0x12021201, 0x10001011, 0x10001012, + 0x10001111, 0x10001212, 0x10011011, 0x10011110, 0x10011111, 0x10011112, 0x10011211, 0x10021010, + 0x10021111, 0x10021212, 0x11001011, 0x11001110, 0x11001111, 0x11001112, 0x11001211, 0x11011010, + 0x11011011, 0x11011110, 0x11011111, 0x11011112, 0x11011210, 0x11011211, 0x11021011, 0x11021110, + 0x11021111, 0x11021112, 0x11021211, 0x12001012, 0x12001110, 0x12001111, 0x12001210, 0x12011011, + 0x12011110, 0x12011111, 0x12011112, 0x12011211, 0x12011212, 0x12021111, 0x12021210, 0x12021212, + 0x10001021, 0x10001121, 0x10001221, 0x10011120, 0x10011121, 0x10011220, 0x10011222, 0x10021021, + 0x10021120, 0x10021221, 0x11001020, 0x11001022, 0x11001121, 0x11001220, 0x11011020, 0x11011021, + 0x11011022, 0x11011121, 0x11011122, 0x11011221, 0x11021022, 0x11021121, 0x11021220, 0x12001021, + 0x12001121, 0x12001222, 0x12011120, 0x12011121, 0x12021021, 0x12021120, 0x12021122, 0x10002101, + 0x10012001, 0x10012101, 0x10012202, 0x10022101, 0x11002002, 0x11002201, 0x11012000, 0x11012101, + 0x11012200, 0x11022001, 0x11022100, 0x11022102, 0x11022201, 0x12002101, 0x12012001, 0x12012100, + 0x12012102, 0x12012201, 0x12022101, 0x10002011, 0x10002111, 0x10002112, 0x10002212, 0x10012010, + 0x10012110, 0x10012111, 0x10012210, 0x10022011, 0x10022110, 0x10022112, 0x11002010, 0x11002111, + 0x11002212, 0x11012011, 0x11012012, 0x11012110, 0x11012111, 0x11012112, 0x11012211, 0x11022010, + 0x11022012, 0x11022111, 0x11022112, 0x11022212, 0x12002112, 0x12002211, 0x12012012, 0x12012111, + 0x12012112, 0x12012210, 0x12022011, 0x12022110, 0x12022112, 0x12022211, 0x10012122, 0x11002120, + 0x11002122, 0x11002221, 0x11012121, 0x11012220, 0x11012222, 0x11022120, 0x11022221, 0x12012120, + 0x12022121, 0x10100001, 0x10100100, 0x10100101, 0x10100102, 0x10100201, 0x10110002, 0x10110101, + 0x10110202, 0x10120001, 0x10120100, 0x10120201, 0x11100000, 0x11100101, 0x11100200, 0x11110001, + 0x11110100, 0x11110101, 0x11110102, 0x11110201, 0x11120101, 0x11120200, 0x12100102, 0x12100201, + 0x12110101, 0x12110200, 0x12120000, 0x12120001, 0x12120102, 0x12120201, 0x10100111, 0x10100210, + 0x10100211, 0x10100212, 0x10110011, 0x10110110, 0x10110111, 0x10110112, 0x10110210, 0x10110211, + 0x10120010, 0x10120111, 0x10120112, 0x10120210, 0x10120212, 0x11100011, 0x11100110, 0x11100111, + 0x11100112, 0x11100211, 0x11110010, 0x11110011, 0x11110012, 0x11110110, 0x11110111, 0x11110112, + 0x11110210, 0x11110211, 0x11110212, 0x11120011, 0x11120110, 0x11120111, 0x11120112, 0x11120211, + 0x12100012, 0x12100111, 0x12110011, 0x12110110, 0x12110111, 0x12110112, 0x12110211, 0x12120010, + 0x12120111, 0x12120212, 0x10100021, 0x10100122, 0x10110022, 0x10110121, 0x10110222, 0x10120021, + 0x10120120, 0x11100022, 0x11100121, 0x11100222, 0x11110021, 0x11110120, 0x11110121, 0x11110122, + 0x11110221, 0x11120022, 0x11120121, 0x12100121, 0x12110020, 0x12110022, 0x12110121, 0x12110221, + 0x12110222, 0x12120120, 0x10101100, 0x10101101, 0x10111001, 0x10111100, 0x10111101, 0x10111102, + 0x10111200, 0x10111201, 0x10121001, 0x10121101, 0x10121200, 0x10121202, 0x11101001, 0x11101100, + 0x11101101, 0x11101102, 0x11101201, 0x11101202, 0x11111000, 0x11111001, 0x11111100, 0x11111101, + 0x11111102, 0x11111200, 0x11111201, 0x11111202, 0x11121001, 0x11121002, 0x11121100, 0x11121101, + 0x11121102, 0x11121201, 0x12101000, 0x12101200, 0x12101202, 0x12111001, 0x12111100, 0x12111101, + 0x12111102, 0x12111201, 0x12121001, 0x12121100, 0x12121101, 0x12121202, 0x10101011, 0x10101012, + 0x10101110, 0x10101111, 0x10101112, 0x10101211, 0x10111010, 0x10111011, 0x10111012, 0x10111110, + 0x10111111, 0x10111112, 0x10111211, 0x10111212, 0x10121011, 0x10121110, 0x10121111, 0x10121112, + 0x10121211, 0x11101010, 0x11101011, 0x11101012, 0x11101110, 0x11101111, 0x11101112, 0x11101210, + 0x11101211, 0x11111010, 0x11111011, 0x11111012, 0x11111110, 0x11111111, 0x11111112, 0x11111210, + 0x11111211, 0x11111212, 0x11121010, 0x11121011, 0x11121110, 0x11121111, 0x11121112, 0x11121210, + 0x11121211, 0x11121212, 0x12101011, 0x12101110, 0x12101111, 0x12101211, 0x12101212, 0x12111010, + 0x12111011, 0x12111110, 0x12111111, 0x12111112, 0x12111210, 0x12111211, 0x12121011, 0x12121110, + 0x12121111, 0x12121112, 0x12121211, 0x10101020, 0x10101021, 0x10101022, 0x10101120, 0x10101122, + 0x10101220, 0x10101221, 0x10111021, 0x10111120, 0x10111121, 0x10111220, 0x10111221, 0x10121020, + 0x10121021, 0x10121022, 0x10121120, 0x10121121, 0x10121122, 0x10121220, 0x10121221, 0x11101021, + 0x11101121, 0x11101122, 0x11101220, 0x11101221, 0x11101222, 0x11111020, 0x11111021, 0x11111022, + 0x11111120, 0x11111121, 0x11111122, 0x11111220, 0x11111221, 0x11111222, 0x11121021, 0x11121120, + 0x11121121, 0x11121221, 0x12101022, 0x12101121, 0x12101122, 0x12101220, 0x12101221, 0x12101222, + 0x12111021, 0x12111121, 0x12111222, 0x12121022, 0x12121121, 0x12121122, 0x12121220, 0x12121221, + 0x10102100, 0x10102101, 0x10102102, 0x10102201, 0x10112000, 0x10112101, 0x10112200, 0x10122001, + 0x10122202, 0x11102101, 0x11102200, 0x11102202, 0x11112001, 0x11112100, 0x11112101, 0x11112102, + 0x11112200, 0x11112201, 0x11122000, 0x11122002, 0x11122100, 0x11122101, 0x12102002, 0x12102201, + 0x12112000, 0x12112002, 0x12112101, 0x12112200, 0x12122001, 0x12122201, 0x10102011, 0x10102012, + 0x10102111, 0x10102212, 0x10112011, 0x10112110, 0x10112111, 0x10112112, 0x10112211, 0x10122111, + 0x11102011, 0x11102110, 0x11102111, 0x11102112, 0x11102211, 0x11112010, 0x11112011, 0x11112012, + 0x11112110, 0x11112111, 0x11112112, 0x11112210, 0x11112211, 0x11112212, 0x11122011, 0x11122110, + 0x11122111, 0x11122112, 0x11122211, 0x12102011, 0x12102111, 0x12102211, 0x12112011, 0x12112110, + 0x12112111, 0x12112112, 0x12112210, 0x12112211, 0x12122111, 0x10102120, 0x10102220, 0x10112121, + 0x10112222, 0x10122020, 0x10122121, 0x10122122, 0x10122221, 0x11102121, 0x11102220, 0x11102221, + 0x11112021, 0x11112121, 0x11112122, 0x11112220, 0x11112221, 0x11122022, 0x11122121, 0x11122220, + 0x11122222, 0x12102021, 0x12102222, 0x12112022, 0x12112121, 0x12112122, 0x12112220, 0x12112222, + 0x12122021, 0x10200101, 0x10210100, 0x10210102, 0x10210201, 0x10220101, 0x11200100, 0x11210000, + 0x11210101, 0x11210102, 0x11210200, 0x11210202, 0x11220001, 0x11220100, 0x11220102, 0x11220201, + 0x12200001, 0x12210102, 0x12220101, 0x10200011, 0x10200110, 0x10200112, 0x10200211, 0x10210012, + 0x10210111, 0x10220011, 0x10220012, 0x10220112, 0x10220211, 0x11200111, 0x11200211, 0x11210011, + 0x11210111, 0x11210112, 0x11210211, 0x11220111, 0x11220112, 0x11220212, 0x12200110, 0x12200212, + 0x12210012, 0x12210111, 0x12220011, 0x12220112, 0x12220211, 0x10210021, 0x10210122, 0x10210221, + 0x11200020, 0x11200021, 0x11200122, 0x11210121, 0x11210122, 0x11210220, 0x11220020, 0x12200121, + 0x12210021, 0x12210122, 0x12220121, 0x10211001, 0x10211002, 0x10211101, 0x10211102, 0x10211202, + 0x10221001, 0x10221102, 0x10221201, 0x11201000, 0x11201002, 0x11201101, 0x11201200, 0x11201202, + 0x11211001, 0x11211100, 0x11211101, 0x11211102, 0x11211201, 0x11211202, 0x11221000, 0x11221002, + 0x11221101, 0x12201100, 0x12201101, 0x12201201, 0x12211000, 0x12211002, 0x12211100, 0x12211101, + 0x12211102, 0x12211200, 0x12211202, 0x12221001, 0x12221100, 0x12221201, 0x10201111, 0x10201210, + 0x10201212, 0x10211011, 0x10211111, 0x10211112, 0x10211211, 0x11201110, 0x11201111, 0x11201112, + 0x11201211, 0x11211010, 0x11211011, 0x11211110, 0x11211111, 0x11211112, 0x11211211, 0x11221011, + 0x11221110, 0x11221111, 0x11221112, 0x11221211, 0x12201112, 0x12201211, 0x12201212, 0x12211011, + 0x12211111, 0x12211112, 0x12211211, 0x12211212, 0x12221012, 0x12221111, 0x12221112, 0x12221210, + 0x10201022, 0x10201221, 0x10211121, 0x10221020, 0x10221122, 0x10221220, 0x10221221, 0x11201020, + 0x11201121, 0x11201220, 0x11201222, 0x11211021, 0x11211120, 0x11211121, 0x11211122, 0x11211220, + 0x11211222, 0x11221020, 0x11221121, 0x11221220, 0x12201020, 0x12201022, 0x12201121, 0x12201222, + 0x12211120, 0x12211122, 0x12211220, 0x12211221, 0x12221020, 0x12221120, 0x12221122, 0x12221222, + 0x10212102, 0x10212201, 0x10222101, 0x11202001, 0x11212002, 0x11212101, 0x11212202, 0x11222001, + 0x11222201, 0x12202101, 0x12212001, 0x12212200, 0x12222102, 0x10202011, 0x10202110, 0x10212010, + 0x10212111, 0x10222011, 0x10222110, 0x10222112, 0x10222211, 0x11202010, 0x11202011, 0x11202111, + 0x11202112, 0x11202210, 0x11212011, 0x11212110, 0x11212111, 0x11212112, 0x11212211, 0x11222010, + 0x11222111, 0x11222212, 0x12202012, 0x12202110, 0x12202212, 0x12212111, 0x12222011, 0x12222110, + 0x12222111, 0x12222211, 0x10212021, 0x10212122, 0x10212220, 0x11202021, 0x11202120, 0x11202221, + 0x11212020, 0x11212121, 0x11212220, 0x11212222, 0x11222120, 0x11222121, 0x11222221, 0x12202122, + 0x12212120, 0x12212220, 0x12212222, 0x12222122, 0x20000000, 0x20000002, 0x20000200, 0x20000202, + 0x20020000, 0x20020002, 0x20020200, 0x20020202, 0x21000101, 0x21010000, 0x21010001, 0x21010100, + 0x21010102, 0x21010201, 0x21020101, 0x22000000, 0x22000002, 0x22000200, 0x22000202, 0x22010101, + 0x22020000, 0x22020002, 0x22020200, 0x22020202, 0x20000111, 0x20010011, 0x20010110, 0x20010112, + 0x20010211, 0x20020111, 0x21000011, 0x21000110, 0x21000211, 0x21010010, 0x21010012, 0x21010111, + 0x21010112, 0x21010210, 0x21010211, 0x21020110, 0x21020112, 0x21020211, 0x22000111, 0x22000211, + 0x22010110, 0x22010112, 0x22010211, 0x22020111, 0x20000020, 0x20000022, 0x20000220, 0x20000222, + 0x20010121, 0x20020020, 0x20020022, 0x20020220, 0x20020222, 0x21010021, 0x21010120, 0x21010221, + 0x21020121, 0x22000020, 0x22000022, 0x22000220, 0x22000222, 0x22010121, 0x22020020, 0x22020022, + 0x22020220, 0x22020222, 0x20011100, 0x20011201, 0x21001001, 0x21001100, 0x21011001, 0x21011101, + 0x21011202, 0x21021001, 0x21021100, 0x21021201, 0x22011100, 0x22011201, 0x20001011, 0x20001211, + 0x20011012, 0x20011111, 0x20011212, 0x20021112, 0x20021211, 0x21001010, 0x21001011, 0x21001111, + 0x21001210, 0x21011011, 0x21011110, 0x21011111, 0x21011112, 0x21011211, 0x21011212, 0x21021111, + 0x21021112, 0x21021210, 0x21021212, 0x22001011, 0x22001110, 0x22001112, 0x22001211, 0x22011010, + 0x22011012, 0x22011111, 0x22011210, 0x22021112, 0x20011021, 0x20011122, 0x20011221, 0x20021121, + 0x21001021, 0x21001120, 0x21001221, 0x21001222, 0x21011020, 0x21011121, 0x21011221, 0x21011222, + 0x21021021, 0x21021122, 0x21021222, 0x22001121, 0x22011021, 0x22011222, 0x22021120, 0x20002000, + 0x20002002, 0x20002200, 0x20002202, 0x20012101, 0x20022000, 0x20022002, 0x20022200, 0x20022202, + 0x21002001, 0x21002101, 0x21012001, 0x21012100, 0x21012201, 0x21022101, 0x21022201, 0x22002000, + 0x22002002, 0x22002200, 0x22002202, 0x22012101, 0x22022000, 0x22022002, 0x22022200, 0x22022202, + 0x20002111, 0x20002112, 0x20012011, 0x20012110, 0x20012112, 0x20022111, 0x21002011, 0x21002110, + 0x21002112, 0x21002211, 0x21012010, 0x21012012, 0x21012111, 0x21012212, 0x21022011, 0x21022110, + 0x22002111, 0x22012112, 0x22012211, 0x22022111, 0x20002020, 0x20002022, 0x20002220, 0x20002222, + 0x20012121, 0x20022020, 0x20022022, 0x20022220, 0x20022222, 0x21002121, 0x21012021, 0x21012120, + 0x21012122, 0x22002020, 0x22002022, 0x22002220, 0x22002222, 0x22012121, 0x22022020, 0x22022022, + 0x22022220, 0x22022222, 0x20100101, 0x20110001, 0x20110102, 0x20110200, 0x20110201, 0x20120101, + 0x21100001, 0x21100102, 0x21100201, 0x21110101, 0x21110200, 0x21110202, 0x21120201, 0x21120202, + 0x22100101, 0x22110001, 0x22110100, 0x22110102, 0x22110201, 0x22120101, 0x20100011, 0x20100110, + 0x20100112, 0x20100211, 0x20110010, 0x20110111, 0x20110210, 0x20110212, 0x20120011, 0x20120110, + 0x20120112, 0x20120211, 0x21100010, 0x21100111, 0x21110010, 0x21110011, 0x21110110, 0x21110111, + 0x21110112, 0x21110211, 0x21120012, 0x21120111, 0x22100110, 0x22100112, 0x22110012, 0x22110111, + 0x22110210, 0x22120011, 0x22120110, 0x22120112, 0x22120211, 0x20100121, 0x20110021, 0x20110120, + 0x20110221, 0x20120121, 0x21100120, 0x21100122, 0x21100221, 0x21110020, 0x21110022, 0x21110121, + 0x21110220, 0x21120122, 0x21120221, 0x22100121, 0x22110120, 0x22110122, 0x22120221, 0x20101001, + 0x20101100, 0x20101102, 0x20111000, 0x20111101, 0x20111200, 0x20121102, 0x21101000, 0x21101202, + 0x21111001, 0x21111100, 0x21111101, 0x21111102, 0x21111200, 0x21111201, 0x21121000, 0x21121001, + 0x21121002, 0x21121101, 0x22101100, 0x22101102, 0x22111002, 0x22111100, 0x22111101, 0x22111200, + 0x22121001, 0x22121201, 0x20101010, 0x20101111, 0x20101210, 0x20101212, 0x20111010, 0x20111011, + 0x20111110, 0x20111111, 0x20111112, 0x20111211, 0x20121011, 0x20121111, 0x20121211, 0x20121212, + 0x21101011, 0x21101110, 0x21101111, 0x21101112, 0x21101211, 0x21111010, 0x21111011, 0x21111012, + 0x21111110, 0x21111111, 0x21111112, 0x21111210, 0x21111211, 0x21111212, 0x21121011, 0x21121110, + 0x21121111, 0x21121112, 0x21121211, 0x22101011, 0x22101111, 0x22101210, 0x22111011, 0x22111012, + 0x22111110, 0x22111111, 0x22111112, 0x22111211, 0x22111212, 0x22121010, 0x22121012, 0x22121111, + 0x22121210, 0x22121212, 0x20101021, 0x20101120, 0x20111020, 0x20111121, 0x20111221, 0x20121020, + 0x20121122, 0x20121221, 0x21101121, 0x21101220, 0x21101221, 0x21111021, 0x21111022, 0x21111121, + 0x21111122, 0x21111221, 0x21121121, 0x21121220, 0x22101022, 0x22101120, 0x22101221, 0x22101222, + 0x22111022, 0x22111120, 0x22111121, 0x22121120, 0x22121122, 0x22121221, 0x20102101, 0x20112102, + 0x20112201, 0x20122101, 0x21102001, 0x21102102, 0x21112000, 0x21112002, 0x21112101, 0x21112102, + 0x21112202, 0x21122100, 0x21122101, 0x22102101, 0x22112001, 0x22112102, 0x22112201, 0x22122101, + 0x20102110, 0x20102112, 0x20102211, 0x20112010, 0x20112012, 0x20112111, 0x20112210, 0x20112212, + 0x20122010, 0x20122011, 0x20122110, 0x20122112, 0x21102010, 0x21102012, 0x21102111, 0x21102210, + 0x21102212, 0x21112011, 0x21112110, 0x21112111, 0x21112112, 0x21112211, 0x21122012, 0x21122111, + 0x21122112, 0x21122212, 0x22102011, 0x22102110, 0x22112010, 0x22112012, 0x22112111, 0x22112212, + 0x22122011, 0x22122112, 0x20102121, 0x20112121, 0x20122121, 0x21102120, 0x21102122, 0x21102221, + 0x21112020, 0x21112121, 0x21112220, 0x21122021, 0x22102121, 0x22112021, 0x22112120, 0x22112121, + 0x22112122, 0x20200000, 0x20200002, 0x20200200, 0x20200202, 0x20210101, 0x20220000, 0x20220002, + 0x20220200, 0x20220202, 0x21200101, 0x21210001, 0x21210100, 0x21210102, 0x21210201, 0x22200000, + 0x22200002, 0x22200200, 0x22200202, 0x22210101, 0x22220000, 0x22220002, 0x22220200, 0x22220202, + 0x20200111, 0x20200211, 0x20210011, 0x20210110, 0x20210112, 0x20210211, 0x20210212, 0x21200112, + 0x21200211, 0x21210011, 0x21210111, 0x21210210, 0x21210212, 0x21220011, 0x21220110, 0x22200111, + 0x22210010, 0x22210012, 0x22210112, 0x22210211, 0x20200022, 0x20200220, 0x20200222, 0x20210020, + 0x20210221, 0x20220022, 0x20220220, 0x20220222, 0x21200121, 0x21210021, 0x21210122, 0x21210221, + 0x21220121, 0x22200020, 0x22200022, 0x22200220, 0x22200222, 0x22210121, 0x22220020, 0x22220022, + 0x22220220, 0x22220222, 0x20211201, 0x20221101, 0x21201001, 0x21201100, 0x21211000, 0x21211100, + 0x21211101, 0x21211200, 0x21211202, 0x21221001, 0x21221101, 0x21221102, 0x21221200, 0x21221201, + 0x22201101, 0x20201112, 0x20201211, 0x20211010, 0x20211012, 0x20211111, 0x20211210, 0x20221112, + 0x20221211, 0x21201012, 0x21201111, 0x21211011, 0x21211110, 0x21211111, 0x21211112, 0x21211211, + 0x21221111, 0x21221212, 0x22201011, 0x22201110, 0x22201111, 0x22201112, 0x22201211, 0x22211012, + 0x22211111, 0x22211210, 0x20201121, 0x20211021, 0x20211122, 0x20211222, 0x20221021, 0x20221121, + 0x21201120, 0x21201122, 0x21201222, 0x21211022, 0x21211121, 0x21211122, 0x21211220, 0x21221020, + 0x21221022, 0x22201122, 0x22211020, 0x22211121, 0x22211122, 0x22211221, 0x22221021, 0x22221120, + 0x22221122, 0x20202000, 0x20202002, 0x20202200, 0x20202202, 0x20222000, 0x20222002, 0x20222200, + 0x20222202, 0x21212001, 0x21212100, 0x21212102, 0x21212201, 0x22202000, 0x22202002, 0x22202200, + 0x22202202, 0x22212101, 0x22222000, 0x22222002, 0x22222200, 0x22222202, 0x20202111, 0x20212110, + 0x20212211, 0x20222011, 0x20222111, 0x21202011, 0x21212010, 0x21212111, 0x21212212, 0x21222011, + 0x21222112, 0x21222211, 0x22212010, 0x22212112, 0x20202020, 0x20202022, 0x20202220, 0x20202222, + 0x20222020, 0x20222022, 0x20222220, 0x20222222, 0x21212021, 0x21212120, 0x21212122, 0x22202020, + 0x22202022, 0x22202220, 0x22202222, 0x22212121, 0x22222020, 0x22222022, 0x22222220, 0x22222222, +GGML_TABLE_END() +#endif + +#endif // GGML_COMMON_IMPL +#endif // GGML_COMMON_IMPL diff --git a/bindings/ruby/ext/ggml-cuda.h b/bindings/ruby/ext/ggml-cuda.h new file mode 100644 index 0000000000000000000000000000000000000000..5eb4af40f4d1fef5847c37bed27dfc99d3a07a4a --- /dev/null +++ b/bindings/ruby/ext/ggml-cuda.h @@ -0,0 +1,43 @@ +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#ifdef GGML_USE_HIPBLAS +#define GGML_CUDA_NAME "ROCm" +#define GGML_CUBLAS_NAME "hipBLAS" +#else +#define GGML_CUDA_NAME "CUDA" +#define GGML_CUBLAS_NAME "cuBLAS" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define GGML_CUDA_MAX_DEVICES 16 + +// backend API +GGML_API GGML_CALL ggml_backend_t ggml_backend_cuda_init(int device); + +GGML_API GGML_CALL bool ggml_backend_is_cuda(ggml_backend_t backend); + +// device buffer +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_cuda_buffer_type(int device); + +// split tensor buffer that splits matrices by rows across multiple devices +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_cuda_split_buffer_type(const float * tensor_split); + +// pinned host buffer for use with the CPU backend for faster copies between CPU and GPU +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_cuda_host_buffer_type(void); + +GGML_API GGML_CALL int ggml_backend_cuda_get_device_count(void); +GGML_API GGML_CALL void ggml_backend_cuda_get_device_description(int device, char * description, size_t description_size); +GGML_API GGML_CALL void ggml_backend_cuda_get_device_memory(int device, size_t * free, size_t * total); + +GGML_API GGML_CALL bool ggml_backend_cuda_register_host_buffer(void * buffer, size_t size); +GGML_API GGML_CALL void ggml_backend_cuda_unregister_host_buffer(void * buffer); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-impl.h b/bindings/ruby/ext/ggml-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..93a4f1a2b72780d4cf42abfdfdc4b476c607bba5 --- /dev/null +++ b/bindings/ruby/ext/ggml-impl.h @@ -0,0 +1,272 @@ +#pragma once + +#include "ggml.h" + +// GGML internal header + +#include +#include // load `stdlib.h` before other headers to work around MinGW bug: https://sourceforge.net/p/mingw-w64/bugs/192/ +#include +#include +#include // memcpy +#include // fabsf + +#ifdef __cplusplus +extern "C" { +#endif + +// static_assert should be a #define, but if it's not, +// fall back to the _Static_assert C11 keyword. +// if C99 - static_assert is noop +// ref: https://stackoverflow.com/a/53923785/4039976 +#ifndef __cplusplus +#ifndef static_assert +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201100L) +#define static_assert(cond, msg) _Static_assert(cond, msg) +#else +#define static_assert(cond, msg) struct global_scope_noop_trick +#endif +#endif +#endif + +// __FMA__ and __F16C__ are not defined in MSVC, however they are implied with AVX2/AVX512 +#if defined(_MSC_VER) && (defined(__AVX2__) || defined(__AVX512F__)) +#ifndef __FMA__ +#define __FMA__ +#endif +#ifndef __F16C__ +#define __F16C__ +#endif +#endif + +// __SSE3__ and __SSSE3__ are not defined in MSVC, but SSE3/SSSE3 are present when AVX/AVX2/AVX512 are available +#if defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)) +#ifndef __SSE3__ +#define __SSE3__ +#endif +#ifndef __SSSE3__ +#define __SSSE3__ +#endif +#endif + +// 16-bit float +// on Arm, we use __fp16 +// on x86, we use uint16_t +#if defined(__ARM_NEON) && !defined(_MSC_VER) + +// if YCM cannot find , make a symbolic link to it, for example: +// +// $ ln -sfn /Library/Developer/CommandLineTools/usr/lib/clang/13.1.6/include/arm_neon.h ./src/ +// +#include + +typedef __fp16 ggml_fp16_internal_t; + +#define GGML_COMPUTE_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) ggml_compute_fp32_to_fp16(x) + +#define GGML_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) + +static inline float ggml_compute_fp16_to_fp32(ggml_fp16_t h) { + ggml_fp16_internal_t tmp; + memcpy(&tmp, &h, sizeof(ggml_fp16_t)); + return (float)tmp; +} + +static inline ggml_fp16_t ggml_compute_fp32_to_fp16(float f) { + ggml_fp16_t res; + ggml_fp16_internal_t tmp = f; + memcpy(&res, &tmp, sizeof(ggml_fp16_t)); + return res; +} + +#else + +typedef uint16_t ggml_fp16_internal_t; + +#ifdef __wasm_simd128__ +#include +#else +#ifdef __POWER9_VECTOR__ +#include +#undef bool +#define bool _Bool +#else +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#else +#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) || defined(__SSE3__) +#if !defined(__riscv) +#include +#endif +#endif +#endif +#endif +#endif + +#ifdef __riscv_v_intrinsic +#include +#endif + +#ifdef __F16C__ + +#ifdef _MSC_VER +#define GGML_COMPUTE_FP16_TO_FP32(x) _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(x))) +#define GGML_COMPUTE_FP32_TO_FP16(x) _mm_extract_epi16(_mm_cvtps_ph(_mm_set_ss(x), 0), 0) +#else +#define GGML_COMPUTE_FP16_TO_FP32(x) _cvtsh_ss(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) _cvtss_sh(x, 0) +#endif + +#elif defined(__POWER9_VECTOR__) + +#define GGML_COMPUTE_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) ggml_compute_fp32_to_fp16(x) +/* the inline asm below is about 12% faster than the lookup method */ +#define GGML_FP16_TO_FP32(x) GGML_COMPUTE_FP16_TO_FP32(x) +#define GGML_FP32_TO_FP16(x) GGML_COMPUTE_FP32_TO_FP16(x) + +static inline float ggml_compute_fp16_to_fp32(ggml_fp16_t h) { + register float f; + register double d; + __asm__( + "mtfprd %0,%2\n" + "xscvhpdp %0,%0\n" + "frsp %1,%0\n" : + /* temp */ "=d"(d), + /* out */ "=f"(f): + /* in */ "r"(h)); + return f; +} + +static inline ggml_fp16_t ggml_compute_fp32_to_fp16(float f) { + register double d; + register ggml_fp16_t r; + __asm__( /* xscvdphp can work on double or single precision */ + "xscvdphp %0,%2\n" + "mffprd %1,%0\n" : + /* temp */ "=d"(d), + /* out */ "=r"(r): + /* in */ "f"(f)); + return r; +} + +#else + +// FP16 <-> FP32 +// ref: https://github.com/Maratyszcza/FP16 + +static inline float fp32_from_bits(uint32_t w) { + union { + uint32_t as_bits; + float as_value; + } fp32; + fp32.as_bits = w; + return fp32.as_value; +} + +static inline uint32_t fp32_to_bits(float f) { + union { + float as_value; + uint32_t as_bits; + } fp32; + fp32.as_value = f; + return fp32.as_bits; +} + +static inline float ggml_compute_fp16_to_fp32(ggml_fp16_t h) { + const uint32_t w = (uint32_t) h << 16; + const uint32_t sign = w & UINT32_C(0x80000000); + const uint32_t two_w = w + w; + + const uint32_t exp_offset = UINT32_C(0xE0) << 23; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__) + const float exp_scale = 0x1.0p-112f; +#else + const float exp_scale = fp32_from_bits(UINT32_C(0x7800000)); +#endif + const float normalized_value = fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale; + + const uint32_t magic_mask = UINT32_C(126) << 23; + const float magic_bias = 0.5f; + const float denormalized_value = fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias; + + const uint32_t denormalized_cutoff = UINT32_C(1) << 27; + const uint32_t result = sign | + (two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) : fp32_to_bits(normalized_value)); + return fp32_from_bits(result); +} + +static inline ggml_fp16_t ggml_compute_fp32_to_fp16(float f) { +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__) + const float scale_to_inf = 0x1.0p+112f; + const float scale_to_zero = 0x1.0p-110f; +#else + const float scale_to_inf = fp32_from_bits(UINT32_C(0x77800000)); + const float scale_to_zero = fp32_from_bits(UINT32_C(0x08800000)); +#endif + float base = (fabsf(f) * scale_to_inf) * scale_to_zero; + + const uint32_t w = fp32_to_bits(f); + const uint32_t shl1_w = w + w; + const uint32_t sign = w & UINT32_C(0x80000000); + uint32_t bias = shl1_w & UINT32_C(0xFF000000); + if (bias < UINT32_C(0x71000000)) { + bias = UINT32_C(0x71000000); + } + + base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base; + const uint32_t bits = fp32_to_bits(base); + const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00); + const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF); + const uint32_t nonsign = exp_bits + mantissa_bits; + return (sign >> 16) | (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign); +} + +#define GGML_COMPUTE_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) ggml_compute_fp32_to_fp16(x) + +#endif // __F16C__ + +#endif // __ARM_NEON + +// precomputed f32 table for f16 (256 KB) +// defined in ggml.c, initialized in ggml_init() +extern float ggml_table_f32_f16[1 << 16]; + +// On ARM NEON, it's quicker to directly convert x -> x instead of calling into ggml_lookup_fp16_to_fp32, +// so we define GGML_FP16_TO_FP32 and GGML_FP32_TO_FP16 elsewhere for NEON. +// This is also true for POWER9. +#if !defined(GGML_FP16_TO_FP32) +inline static float ggml_lookup_fp16_to_fp32(ggml_fp16_t f) { + uint16_t s; + memcpy(&s, &f, sizeof(uint16_t)); + return ggml_table_f32_f16[s]; +} + +#define GGML_FP16_TO_FP32(x) ggml_lookup_fp16_to_fp32(x) +#endif + +#if !defined(GGML_FP32_TO_FP16) +#define GGML_FP32_TO_FP16(x) GGML_COMPUTE_FP32_TO_FP16(x) +#endif + +#define GGML_HASHTABLE_FULL ((size_t)-1) +#define GGML_HASHTABLE_ALREADY_EXISTS ((size_t)-2) + +struct ggml_hash_set ggml_hash_set_new(size_t size); + +bool ggml_hash_contains (const struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// returns GGML_HASHTABLE_FULL if table is full, otherwise the current index of the key or where it should be inserted +size_t ggml_hash_find (const struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// returns GGML_HASHTABLE_ALREADY_EXISTS if key already exists, index otherwise, asserts if table is full +size_t ggml_hash_insert ( struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// return index, asserts if table is full +size_t ggml_hash_find_or_insert( struct ggml_hash_set hash_set, struct ggml_tensor * key); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-kompute.h b/bindings/ruby/ext/ggml-kompute.h new file mode 100644 index 0000000000000000000000000000000000000000..171465456a5b17a6e27ebe326703c260c65a3773 --- /dev/null +++ b/bindings/ruby/ext/ggml-kompute.h @@ -0,0 +1,46 @@ +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ggml_vk_device { + int index; + int type; // same as VkPhysicalDeviceType + size_t heapSize; + const char * name; + const char * vendor; + int subgroupSize; + uint64_t bufferAlignment; + uint64_t maxAlloc; +}; + +struct ggml_vk_device * ggml_vk_available_devices(size_t memoryRequired, size_t * count); +bool ggml_vk_get_device(struct ggml_vk_device * device, size_t memoryRequired, const char * name); +bool ggml_vk_has_vulkan(void); +bool ggml_vk_has_device(void); +struct ggml_vk_device ggml_vk_current_device(void); + +// +// backend API +// + +// forward declaration +typedef struct ggml_backend * ggml_backend_t; + +GGML_API ggml_backend_t ggml_backend_kompute_init(int device); + +GGML_API bool ggml_backend_is_kompute(ggml_backend_t backend); + +GGML_API ggml_backend_buffer_type_t ggml_backend_kompute_buffer_type(int device); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-metal.h b/bindings/ruby/ext/ggml-metal.h new file mode 100644 index 0000000000000000000000000000000000000000..a5c542189c295e504d0f281ed3492888f6389db0 --- /dev/null +++ b/bindings/ruby/ext/ggml-metal.h @@ -0,0 +1,66 @@ +// An interface allowing to compute ggml_cgraph with Metal +// +// This is a fully functional interface that extends ggml with GPU support for Apple devices. +// A similar interface can be created for other GPU backends (e.g. Vulkan, CUDA, OpenCL, etc.) +// +// How it works? +// +// As long as your program can create and evaluate a ggml_cgraph on the CPU, you can use this +// interface to evaluate the same graph on the GPU. Instead of using ggml_graph_compute(), you +// use ggml_metal_graph_compute() (or ggml_vulkan_graph_compute(), etc.) +// +// You only need to make sure that all memory buffers that you used during the graph creation +// are mapped to the device memory with the ggml_metal_add_buffer() function. This mapping is +// used during the graph evaluation to determine the arguments of the compute kernels. +// +// Synchronization between device and host memory (for example for input and output tensors) +// is done with the ggml_metal_set_tensor() and ggml_metal_get_tensor() functions. +// + +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#include +#include + +// max memory buffers that can be mapped to the device +#define GGML_METAL_MAX_BUFFERS 64 + +struct ggml_tensor; +struct ggml_cgraph; + +#ifdef __cplusplus +extern "C" { +#endif + +// +// backend API +// user-code should use only these functions +// + +GGML_API void ggml_backend_metal_log_set_callback(ggml_log_callback log_callback, void * user_data); + +GGML_API ggml_backend_t ggml_backend_metal_init(void); + +GGML_API bool ggml_backend_is_metal(ggml_backend_t backend); + +GGML_API GGML_CALL ggml_backend_buffer_t ggml_backend_metal_buffer_from_ptr(void * data, size_t size, size_t max_size); + +GGML_API void ggml_backend_metal_set_n_cb(ggml_backend_t backend, int n_cb); + +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_metal_buffer_type(void); + +// helper to check if the device supports a specific family +// ideally, the user code should be doing these checks +// ref: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf +GGML_API bool ggml_backend_metal_supports_family(ggml_backend_t backend, int family); + +// capture all command buffers committed the next time `ggml_backend_graph_compute` is called +GGML_API void ggml_backend_metal_capture_next_compute(ggml_backend_t backend); + +#ifdef __cplusplus +} +#endif + diff --git a/bindings/ruby/ext/ggml-opencl.h b/bindings/ruby/ext/ggml-opencl.h new file mode 100644 index 0000000000000000000000000000000000000000..257a6be6af5ec9b6eadc0d4cb5fb3b5e0a7dd82c --- /dev/null +++ b/bindings/ruby/ext/ggml-opencl.h @@ -0,0 +1,36 @@ +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + +GGML_API void ggml_cl_init(void); + +GGML_API void ggml_cl_mul(const struct ggml_tensor * src0, const struct ggml_tensor * src1, struct ggml_tensor * dst); +GGML_API void ggml_cl_add(const struct ggml_tensor * src0, const struct ggml_tensor * src1, struct ggml_tensor * dst); +GGML_API bool ggml_cl_can_mul_mat(const struct ggml_tensor * src0, const struct ggml_tensor * src1, const struct ggml_tensor * dst); +GGML_API size_t ggml_cl_mul_mat_get_wsize(const struct ggml_tensor * src0, const struct ggml_tensor * src1, struct ggml_tensor * dst); +GGML_API void ggml_cl_mul_mat(const struct ggml_tensor * src0, const struct ggml_tensor * src1, struct ggml_tensor * dst, void * wdata, size_t wsize); + +// GGML_API void * ggml_cl_host_malloc(size_t size); +// GGML_API void ggml_cl_host_free(void * ptr); + +GGML_API void ggml_cl_free_data(const struct ggml_tensor* tensor); + +GGML_API void ggml_cl_transform_tensor(void * data, struct ggml_tensor * tensor); + +// backend API + +// GGML_API ggml_backend_t ggml_backend_opencl_init(void); + +// GGML_API bool ggml_backend_is_opencl(ggml_backend_t backend); + +GGML_API ggml_backend_buffer_type_t ggml_backend_opencl_buffer_type(void); +// GGML_API ggml_backend_buffer_type_t ggml_backend_opencl_host_buffer_type(void); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-quants.c b/bindings/ruby/ext/ggml-quants.c new file mode 100644 index 0000000000000000000000000000000000000000..32e84434a8c1b8b271ac44a75f76632726a1c99e --- /dev/null +++ b/bindings/ruby/ext/ggml-quants.c @@ -0,0 +1,12678 @@ +#define GGML_COMMON_IMPL_C +#include "ggml-common.h" + +#include "ggml-quants.h" +#include "ggml-impl.h" + +#define GGML_COMMON_IMPL_C +#include "ggml-common.h" + +#include +#include +#include +#include +#include // for qsort +#include // for GGML_ASSERT + +#ifdef __ARM_NEON + +// if YCM cannot find , make a symbolic link to it, for example: +// +// $ ln -sfn /Library/Developer/CommandLineTools/usr/lib/clang/13.1.6/include/arm_neon.h ./src/ +// +#include + +#else + +#ifdef __wasm_simd128__ +#include +#else +#if defined(__POWER9_VECTOR__) || defined(__powerpc64__) +#include +#undef bool +#define bool _Bool +#else +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#else +#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) || defined(__SSE3__) +#if !defined(__riscv) +#include +#endif +#endif +#endif +#endif +#endif +#endif + +#ifdef __riscv_v_intrinsic +#include +#endif + +#undef MIN +#undef MAX + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define UNUSED GGML_UNUSED + +// some compilers don't provide _mm256_set_m128i, e.g. gcc 7 +#define MM256_SET_M128I(a, b) _mm256_insertf128_si256(_mm256_castsi128_si256(b), (a), 1) + +#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) +// multiply int8_t, add results pairwise twice +static inline __m128i mul_sum_i8_pairs(const __m128i x, const __m128i y) { + // Get absolute values of x vectors + const __m128i ax = _mm_sign_epi8(x, x); + // Sign the values of the y vectors + const __m128i sy = _mm_sign_epi8(y, x); + // Perform multiplication and create 16-bit values + const __m128i dot = _mm_maddubs_epi16(ax, sy); + const __m128i ones = _mm_set1_epi16(1); + return _mm_madd_epi16(ones, dot); +} + +#if __AVX__ || __AVX2__ || __AVX512F__ +// horizontally add 8 floats +static inline float hsum_float_8(const __m256 x) { + __m128 res = _mm256_extractf128_ps(x, 1); + res = _mm_add_ps(res, _mm256_castps256_ps128(x)); + res = _mm_add_ps(res, _mm_movehl_ps(res, res)); + res = _mm_add_ss(res, _mm_movehdup_ps(res)); + return _mm_cvtss_f32(res); +} + +// horizontally add 8 int32_t +static inline int hsum_i32_8(const __m256i a) { + const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(a), _mm256_extractf128_si256(a, 1)); + const __m128i hi64 = _mm_unpackhi_epi64(sum128, sum128); + const __m128i sum64 = _mm_add_epi32(hi64, sum128); + const __m128i hi32 = _mm_shuffle_epi32(sum64, _MM_SHUFFLE(2, 3, 0, 1)); + return _mm_cvtsi128_si32(_mm_add_epi32(sum64, hi32)); +} + +// horizontally add 4 int32_t +static inline int hsum_i32_4(const __m128i a) { + const __m128i hi64 = _mm_unpackhi_epi64(a, a); + const __m128i sum64 = _mm_add_epi32(hi64, a); + const __m128i hi32 = _mm_shuffle_epi32(sum64, _MM_SHUFFLE(2, 3, 0, 1)); + return _mm_cvtsi128_si32(_mm_add_epi32(sum64, hi32)); +} + +#if defined(__AVX2__) || defined(__AVX512F__) +// spread 32 bits to 32 bytes { 0x00, 0xFF } +static inline __m256i bytes_from_bits_32(const uint8_t * x) { + uint32_t x32; + memcpy(&x32, x, sizeof(uint32_t)); + const __m256i shuf_mask = _mm256_set_epi64x( + 0x0303030303030303, 0x0202020202020202, + 0x0101010101010101, 0x0000000000000000); + __m256i bytes = _mm256_shuffle_epi8(_mm256_set1_epi32(x32), shuf_mask); + const __m256i bit_mask = _mm256_set1_epi64x(0x7fbfdfeff7fbfdfe); + bytes = _mm256_or_si256(bytes, bit_mask); + return _mm256_cmpeq_epi8(bytes, _mm256_set1_epi64x(-1)); +} + +// Unpack 32 4-bit fields into 32 bytes +// The output vector contains 32 bytes, each one in [ 0 .. 15 ] interval +static inline __m256i bytes_from_nibbles_32(const uint8_t * rsi) +{ + const __m128i tmp = _mm_loadu_si128((const __m128i *)rsi); + const __m256i bytes = MM256_SET_M128I(_mm_srli_epi16(tmp, 4), tmp); + const __m256i lowMask = _mm256_set1_epi8( 0xF ); + return _mm256_and_si256(lowMask, bytes); +} + +// add int16_t pairwise and return as float vector +static inline __m256 sum_i16_pairs_float(const __m256i x) { + const __m256i ones = _mm256_set1_epi16(1); + const __m256i summed_pairs = _mm256_madd_epi16(ones, x); + return _mm256_cvtepi32_ps(summed_pairs); +} + +static inline __m256 mul_sum_us8_pairs_float(const __m256i ax, const __m256i sy) { +#if defined(__AVXVNNI__) || defined(__AVX512VNNI__) + const __m256i zero = _mm256_setzero_si256(); + const __m256i summed_pairs = _mm256_dpbusd_epi32(zero, ax, sy); + return _mm256_cvtepi32_ps(summed_pairs); +#else + // Perform multiplication and create 16-bit values + const __m256i dot = _mm256_maddubs_epi16(ax, sy); + return sum_i16_pairs_float(dot); +#endif +} + +// multiply int8_t, add results pairwise twice and return as float vector +static inline __m256 mul_sum_i8_pairs_float(const __m256i x, const __m256i y) { +#if __AVXVNNIINT8__ + const __m256i zero = _mm256_setzero_si256(); + const __m256i summed_pairs = _mm256_dpbssd_epi32(zero, x, y); + return _mm256_cvtepi32_ps(summed_pairs); +#else + // Get absolute values of x vectors + const __m256i ax = _mm256_sign_epi8(x, x); + // Sign the values of the y vectors + const __m256i sy = _mm256_sign_epi8(y, x); + return mul_sum_us8_pairs_float(ax, sy); +#endif +} + +static inline __m128i packNibbles( __m256i bytes ) +{ + // Move bits within 16-bit lanes from 0000_abcd_0000_efgh into 0000_0000_abcd_efgh +#if __AVX512F__ + const __m256i bytes_srli_4 = _mm256_srli_epi16(bytes, 4); // 0000_0000_abcd_0000 + bytes = _mm256_or_si256(bytes, bytes_srli_4); // 0000_abcd_abcd_efgh + return _mm256_cvtepi16_epi8(bytes); // abcd_efgh +#else + const __m256i lowByte = _mm256_set1_epi16( 0xFF ); + __m256i high = _mm256_andnot_si256( lowByte, bytes ); + __m256i low = _mm256_and_si256( lowByte, bytes ); + high = _mm256_srli_epi16( high, 4 ); + bytes = _mm256_or_si256( low, high ); + + // Compress uint16_t lanes into bytes + __m128i r0 = _mm256_castsi256_si128( bytes ); + __m128i r1 = _mm256_extracti128_si256( bytes, 1 ); + return _mm_packus_epi16( r0, r1 ); +#endif +} +#elif defined(__AVX__) +// spread 32 bits to 32 bytes { 0x00, 0xFF } +static inline __m256i bytes_from_bits_32(const uint8_t * x) { + uint32_t x32; + memcpy(&x32, x, sizeof(uint32_t)); + const __m128i shuf_maskl = _mm_set_epi64x(0x0101010101010101, 0x0000000000000000); + const __m128i shuf_maskh = _mm_set_epi64x(0x0303030303030303, 0x0202020202020202); + __m128i bytesl = _mm_shuffle_epi8(_mm_set1_epi32(x32), shuf_maskl); + __m128i bytesh = _mm_shuffle_epi8(_mm_set1_epi32(x32), shuf_maskh); + const __m128i bit_mask = _mm_set1_epi64x(0x7fbfdfeff7fbfdfe); + bytesl = _mm_or_si128(bytesl, bit_mask); + bytesh = _mm_or_si128(bytesh, bit_mask); + bytesl = _mm_cmpeq_epi8(bytesl, _mm_set1_epi64x(-1)); + bytesh = _mm_cmpeq_epi8(bytesh, _mm_set1_epi64x(-1)); + return MM256_SET_M128I(bytesh, bytesl); +} + +// Unpack 32 4-bit fields into 32 bytes +// The output vector contains 32 bytes, each one in [ 0 .. 15 ] interval +static inline __m256i bytes_from_nibbles_32(const uint8_t * rsi) +{ + // Load 16 bytes from memory + __m128i tmpl = _mm_loadu_si128((const __m128i *)rsi); + __m128i tmph = _mm_srli_epi16(tmpl, 4); + const __m128i lowMask = _mm_set1_epi8(0xF); + tmpl = _mm_and_si128(lowMask, tmpl); + tmph = _mm_and_si128(lowMask, tmph); + return MM256_SET_M128I(tmph, tmpl); +} + +// add int16_t pairwise and return as float vector +static inline __m256 sum_i16_pairs_float(const __m128i xh, const __m128i xl) { + const __m128i ones = _mm_set1_epi16(1); + const __m128i summed_pairsl = _mm_madd_epi16(ones, xl); + const __m128i summed_pairsh = _mm_madd_epi16(ones, xh); + const __m256i summed_pairs = MM256_SET_M128I(summed_pairsh, summed_pairsl); + return _mm256_cvtepi32_ps(summed_pairs); +} + +static inline __m256 mul_sum_us8_pairs_float(const __m256i ax, const __m256i sy) { + const __m128i axl = _mm256_castsi256_si128(ax); + const __m128i axh = _mm256_extractf128_si256(ax, 1); + const __m128i syl = _mm256_castsi256_si128(sy); + const __m128i syh = _mm256_extractf128_si256(sy, 1); + // Perform multiplication and create 16-bit values + const __m128i dotl = _mm_maddubs_epi16(axl, syl); + const __m128i doth = _mm_maddubs_epi16(axh, syh); + return sum_i16_pairs_float(doth, dotl); +} + +// multiply int8_t, add results pairwise twice and return as float vector +static inline __m256 mul_sum_i8_pairs_float(const __m256i x, const __m256i y) { + const __m128i xl = _mm256_castsi256_si128(x); + const __m128i xh = _mm256_extractf128_si256(x, 1); + const __m128i yl = _mm256_castsi256_si128(y); + const __m128i yh = _mm256_extractf128_si256(y, 1); + // Get absolute values of x vectors + const __m128i axl = _mm_sign_epi8(xl, xl); + const __m128i axh = _mm_sign_epi8(xh, xh); + // Sign the values of the y vectors + const __m128i syl = _mm_sign_epi8(yl, xl); + const __m128i syh = _mm_sign_epi8(yh, xh); + // Perform multiplication and create 16-bit values + const __m128i dotl = _mm_maddubs_epi16(axl, syl); + const __m128i doth = _mm_maddubs_epi16(axh, syh); + return sum_i16_pairs_float(doth, dotl); +} + +static inline __m128i packNibbles( __m128i bytes1, __m128i bytes2 ) +{ + // Move bits within 16-bit lanes from 0000_abcd_0000_efgh into 0000_0000_abcd_efgh + const __m128i lowByte = _mm_set1_epi16( 0xFF ); + __m128i high = _mm_andnot_si128( lowByte, bytes1 ); + __m128i low = _mm_and_si128( lowByte, bytes1 ); + high = _mm_srli_epi16( high, 4 ); + bytes1 = _mm_or_si128( low, high ); + high = _mm_andnot_si128( lowByte, bytes2 ); + low = _mm_and_si128( lowByte, bytes2 ); + high = _mm_srli_epi16( high, 4 ); + bytes2 = _mm_or_si128( low, high ); + + return _mm_packus_epi16( bytes1, bytes2); +} +#endif +#elif defined(__SSSE3__) +// horizontally add 4x4 floats +static inline float hsum_float_4x4(const __m128 a, const __m128 b, const __m128 c, const __m128 d) { + __m128 res_0 =_mm_hadd_ps(a, b); + __m128 res_1 =_mm_hadd_ps(c, d); + __m128 res =_mm_hadd_ps(res_0, res_1); + res =_mm_hadd_ps(res, res); + res =_mm_hadd_ps(res, res); + + return _mm_cvtss_f32(res); +} +#endif // __AVX__ || __AVX2__ || __AVX512F__ +#endif // defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) + +#if defined(__ARM_NEON) + +#ifdef _MSC_VER + +#define ggml_vld1q_u32(w,x,y,z) { ((w) + ((uint64_t)(x) << 32)), ((y) + ((uint64_t)(z) << 32)) } + +#else + +#define ggml_vld1q_u32(w,x,y,z) { (w), (x), (y), (z) } + +#endif + +#if !defined(__aarch64__) + +// 64-bit compatibility + +// vaddvq_s16 +// vpaddq_s16 +// vpaddq_s32 +// vaddvq_s32 +// vaddvq_f32 +// vmaxvq_f32 +// vcvtnq_s32_f32 +// vzip1_u8 +// vzip2_u8 + +inline static int32_t vaddvq_s16(int16x8_t v) { + return + (int32_t)vgetq_lane_s16(v, 0) + (int32_t)vgetq_lane_s16(v, 1) + + (int32_t)vgetq_lane_s16(v, 2) + (int32_t)vgetq_lane_s16(v, 3) + + (int32_t)vgetq_lane_s16(v, 4) + (int32_t)vgetq_lane_s16(v, 5) + + (int32_t)vgetq_lane_s16(v, 6) + (int32_t)vgetq_lane_s16(v, 7); +} + +inline static int16x8_t vpaddq_s16(int16x8_t a, int16x8_t b) { + int16x4_t a0 = vpadd_s16(vget_low_s16(a), vget_high_s16(a)); + int16x4_t b0 = vpadd_s16(vget_low_s16(b), vget_high_s16(b)); + return vcombine_s16(a0, b0); +} + +inline static int32x4_t vpaddq_s32(int32x4_t a, int32x4_t b) { + int32x2_t a0 = vpadd_s32(vget_low_s32(a), vget_high_s32(a)); + int32x2_t b0 = vpadd_s32(vget_low_s32(b), vget_high_s32(b)); + return vcombine_s32(a0, b0); +} + +inline static int32_t vaddvq_s32(int32x4_t v) { + return vgetq_lane_s32(v, 0) + vgetq_lane_s32(v, 1) + vgetq_lane_s32(v, 2) + vgetq_lane_s32(v, 3); +} + +inline static float vaddvq_f32(float32x4_t v) { + return vgetq_lane_f32(v, 0) + vgetq_lane_f32(v, 1) + vgetq_lane_f32(v, 2) + vgetq_lane_f32(v, 3); +} + +inline static float vmaxvq_f32(float32x4_t v) { + return + MAX(MAX(vgetq_lane_f32(v, 0), vgetq_lane_f32(v, 1)), + MAX(vgetq_lane_f32(v, 2), vgetq_lane_f32(v, 3))); +} + +inline static int32x4_t vcvtnq_s32_f32(float32x4_t v) { + int32x4_t res; + + res[0] = roundf(vgetq_lane_f32(v, 0)); + res[1] = roundf(vgetq_lane_f32(v, 1)); + res[2] = roundf(vgetq_lane_f32(v, 2)); + res[3] = roundf(vgetq_lane_f32(v, 3)); + + return res; +} + +inline static uint8x8_t vzip1_u8(uint8x8_t a, uint8x8_t b) { + uint8x8_t res; + + res[0] = a[0]; res[1] = b[0]; + res[2] = a[1]; res[3] = b[1]; + res[4] = a[2]; res[5] = b[2]; + res[6] = a[3]; res[7] = b[3]; + + return res; +} + +inline static uint8x8_t vzip2_u8(uint8x8_t a, uint8x8_t b) { + uint8x8_t res; + + res[0] = a[4]; res[1] = b[4]; + res[2] = a[5]; res[3] = b[5]; + res[4] = a[6]; res[5] = b[6]; + res[6] = a[7]; res[7] = b[7]; + + return res; +} + +// vld1q_s16_x2 +// vld1q_u8_x2 +// vld1q_u8_x4 +// vld1q_s8_x2 +// vld1q_s8_x4 +// TODO: double-check these work correctly + +typedef struct ggml_int16x8x2_t { + int16x8_t val[2]; +} ggml_int16x8x2_t; + +inline static ggml_int16x8x2_t ggml_vld1q_s16_x2(const int16_t * ptr) { + ggml_int16x8x2_t res; + + res.val[0] = vld1q_s16(ptr + 0); + res.val[1] = vld1q_s16(ptr + 8); + + return res; +} + +typedef struct ggml_uint8x16x2_t { + uint8x16_t val[2]; +} ggml_uint8x16x2_t; + +inline static ggml_uint8x16x2_t ggml_vld1q_u8_x2(const uint8_t * ptr) { + ggml_uint8x16x2_t res; + + res.val[0] = vld1q_u8(ptr + 0); + res.val[1] = vld1q_u8(ptr + 16); + + return res; +} + +typedef struct ggml_uint8x16x4_t { + uint8x16_t val[4]; +} ggml_uint8x16x4_t; + +inline static ggml_uint8x16x4_t ggml_vld1q_u8_x4(const uint8_t * ptr) { + ggml_uint8x16x4_t res; + + res.val[0] = vld1q_u8(ptr + 0); + res.val[1] = vld1q_u8(ptr + 16); + res.val[2] = vld1q_u8(ptr + 32); + res.val[3] = vld1q_u8(ptr + 48); + + return res; +} + +typedef struct ggml_int8x16x2_t { + int8x16_t val[2]; +} ggml_int8x16x2_t; + +inline static ggml_int8x16x2_t ggml_vld1q_s8_x2(const int8_t * ptr) { + ggml_int8x16x2_t res; + + res.val[0] = vld1q_s8(ptr + 0); + res.val[1] = vld1q_s8(ptr + 16); + + return res; +} + +typedef struct ggml_int8x16x4_t { + int8x16_t val[4]; +} ggml_int8x16x4_t; + +inline static ggml_int8x16x4_t ggml_vld1q_s8_x4(const int8_t * ptr) { + ggml_int8x16x4_t res; + + res.val[0] = vld1q_s8(ptr + 0); + res.val[1] = vld1q_s8(ptr + 16); + res.val[2] = vld1q_s8(ptr + 32); + res.val[3] = vld1q_s8(ptr + 48); + + return res; +} + +// NOTE: not tested +inline static int8x16_t ggml_vqtbl1q_s8(int8x16_t a, uint8x16_t b) { + int8x16_t res; + + res[ 0] = a[b[ 0]]; + res[ 1] = a[b[ 1]]; + res[ 2] = a[b[ 2]]; + res[ 3] = a[b[ 3]]; + res[ 4] = a[b[ 4]]; + res[ 5] = a[b[ 5]]; + res[ 6] = a[b[ 6]]; + res[ 7] = a[b[ 7]]; + res[ 8] = a[b[ 8]]; + res[ 9] = a[b[ 9]]; + res[10] = a[b[10]]; + res[11] = a[b[11]]; + res[12] = a[b[12]]; + res[13] = a[b[13]]; + res[14] = a[b[14]]; + res[15] = a[b[15]]; + + return res; +} + +// NOTE: not tested +inline static uint8x16_t ggml_vqtbl1q_u8(uint8x16_t a, uint8x16_t b) { + uint8x16_t res; + + res[ 0] = a[b[ 0]]; + res[ 1] = a[b[ 1]]; + res[ 2] = a[b[ 2]]; + res[ 3] = a[b[ 3]]; + res[ 4] = a[b[ 4]]; + res[ 5] = a[b[ 5]]; + res[ 6] = a[b[ 6]]; + res[ 7] = a[b[ 7]]; + res[ 8] = a[b[ 8]]; + res[ 9] = a[b[ 9]]; + res[10] = a[b[10]]; + res[11] = a[b[11]]; + res[12] = a[b[12]]; + res[13] = a[b[13]]; + res[14] = a[b[14]]; + res[15] = a[b[15]]; + + return res; +} + +#else + +#define ggml_int16x8x2_t int16x8x2_t +#define ggml_uint8x16x2_t uint8x16x2_t +#define ggml_uint8x16x4_t uint8x16x4_t +#define ggml_int8x16x2_t int8x16x2_t +#define ggml_int8x16x4_t int8x16x4_t + +#define ggml_vld1q_s16_x2 vld1q_s16_x2 +#define ggml_vld1q_u8_x2 vld1q_u8_x2 +#define ggml_vld1q_u8_x4 vld1q_u8_x4 +#define ggml_vld1q_s8_x2 vld1q_s8_x2 +#define ggml_vld1q_s8_x4 vld1q_s8_x4 +#define ggml_vqtbl1q_s8 vqtbl1q_s8 +#define ggml_vqtbl1q_u8 vqtbl1q_u8 + +#endif + +#if !defined(__ARM_FEATURE_DOTPROD) + +inline static int32x4_t ggml_vdotq_s32(int32x4_t acc, int8x16_t a, int8x16_t b) { + const int16x8_t p0 = vmull_s8(vget_low_s8 (a), vget_low_s8 (b)); + const int16x8_t p1 = vmull_s8(vget_high_s8(a), vget_high_s8(b)); + + return vaddq_s32(acc, vaddq_s32(vpaddlq_s16(p0), vpaddlq_s16(p1))); +} + +#else + +#define ggml_vdotq_s32(a, b, c) vdotq_s32(a, b, c) + +#endif + +#endif + +#if defined(__ARM_NEON) || defined(__wasm_simd128__) +#define B1(c,s,n) 0x ## n ## c , 0x ## n ## s +#define B2(c,s,n) B1(c,s,n ## c), B1(c,s,n ## s) +#define B3(c,s,n) B2(c,s,n ## c), B2(c,s,n ## s) +#define B4(c,s,n) B3(c,s,n ## c), B3(c,s,n ## s) +#define B5(c,s,n) B4(c,s,n ## c), B4(c,s,n ## s) +#define B6(c,s,n) B5(c,s,n ## c), B5(c,s,n ## s) +#define B7(c,s,n) B6(c,s,n ## c), B6(c,s,n ## s) +#define B8(c,s ) B7(c,s, c), B7(c,s, s) + +// precomputed tables for expanding 8bits to 8 bytes: +static const uint64_t table_b2b_0[1 << 8] = { B8(00, 10) }; // ( b) << 4 +static const uint64_t table_b2b_1[1 << 8] = { B8(10, 00) }; // (!b) << 4 +#endif + +// reference implementation for deterministic creation of model files +void quantize_row_q4_0_reference(const float * restrict x, block_q4_0 * restrict y, int64_t k) { + static const int qk = QK4_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + float max = 0.0f; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + if (amax < fabsf(v)) { + amax = fabsf(v); + max = v; + } + } + + const float d = max / -8; + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < qk/2; ++j) { + const float x0 = x[i*qk + 0 + j]*id; + const float x1 = x[i*qk + qk/2 + j]*id; + + const uint8_t xi0 = MIN(15, (int8_t)(x0 + 8.5f)); + const uint8_t xi1 = MIN(15, (int8_t)(x1 + 8.5f)); + + y[i].qs[j] = xi0; + y[i].qs[j] |= xi1 << 4; + } + } +} + +void quantize_row_q4_0(const float * restrict x, void * restrict y, int64_t k) { + quantize_row_q4_0_reference(x, y, k); +} + + +void quantize_row_q4_1_reference(const float * restrict x, block_q4_1 * restrict y, int64_t k) { + const int qk = QK4_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float min = FLT_MAX; + float max = -FLT_MAX; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + + if (v < min) min = v; + if (v > max) max = v; + } + + const float d = (max - min) / ((1 << 4) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + y[i].m = GGML_FP32_TO_FP16(min); + + for (int j = 0; j < qk/2; ++j) { + const float x0 = (x[i*qk + 0 + j] - min)*id; + const float x1 = (x[i*qk + qk/2 + j] - min)*id; + + const uint8_t xi0 = MIN(15, (int8_t)(x0 + 0.5f)); + const uint8_t xi1 = MIN(15, (int8_t)(x1 + 0.5f)); + + y[i].qs[j] = xi0; + y[i].qs[j] |= xi1 << 4; + } + } +} + +void quantize_row_q4_1(const float * restrict x, void * restrict y, int64_t k) { + quantize_row_q4_1_reference(x, y, k); +} + +void quantize_row_q5_0_reference(const float * restrict x, block_q5_0 * restrict y, int64_t k) { + static const int qk = QK5_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + float max = 0.0f; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + if (amax < fabsf(v)) { + amax = fabsf(v); + max = v; + } + } + + const float d = max / -16; + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + uint32_t qh = 0; + + for (int j = 0; j < qk/2; ++j) { + const float x0 = x[i*qk + 0 + j]*id; + const float x1 = x[i*qk + qk/2 + j]*id; + + const uint8_t xi0 = MIN(31, (int8_t)(x0 + 16.5f)); + const uint8_t xi1 = MIN(31, (int8_t)(x1 + 16.5f)); + + y[i].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + qk/2); + } + + memcpy(&y[i].qh, &qh, sizeof(qh)); + } +} + +void quantize_row_q5_0(const float * restrict x, void * restrict y, int64_t k) { + quantize_row_q5_0_reference(x, y, k); +} + +void quantize_row_q5_1_reference(const float * restrict x, block_q5_1 * restrict y, int64_t k) { + const int qk = QK5_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float min = FLT_MAX; + float max = -FLT_MAX; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + + if (v < min) min = v; + if (v > max) max = v; + } + + const float d = (max - min) / ((1 << 5) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + y[i].m = GGML_FP32_TO_FP16(min); + + uint32_t qh = 0; + + for (int j = 0; j < qk/2; ++j) { + const float x0 = (x[i*qk + 0 + j] - min)*id; + const float x1 = (x[i*qk + qk/2 + j] - min)*id; + + const uint8_t xi0 = (uint8_t)(x0 + 0.5f); + const uint8_t xi1 = (uint8_t)(x1 + 0.5f); + + y[i].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + qk/2); + } + + memcpy(&y[i].qh, &qh, sizeof(y[i].qh)); + } +} + +void quantize_row_q5_1(const float * restrict x, void * restrict y, int64_t k) { + quantize_row_q5_1_reference(x, y, k); +} + +// reference implementation for deterministic creation of model files +void quantize_row_q8_0_reference(const float * restrict x, block_q8_0 * restrict y, int64_t k) { + assert(k % QK8_0 == 0); + const int nb = k / QK8_0; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + + for (int j = 0; j < QK8_0; j++) { + const float v = x[i*QK8_0 + j]; + amax = MAX(amax, fabsf(v)); + } + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < QK8_0; ++j) { + const float x0 = x[i*QK8_0 + j]*id; + + y[i].qs[j] = roundf(x0); + } + } +} + +void quantize_row_q8_0(const float * restrict x, void * restrict vy, int64_t k) { + assert(QK8_0 == 32); + assert(k % QK8_0 == 0); + const int nb = k / QK8_0; + + block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + for (int i = 0; i < nb; i++) { + float32x4_t srcv [8]; + float32x4_t asrcv[8]; + float32x4_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = vld1q_f32(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = vabsq_f32(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = vmaxq_f32(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = vmaxq_f32(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = vmaxq_f32(amaxv[8*j], amaxv[8*j+4]); + + const float amax = vmaxvq_f32(amaxv[0]); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < 8; j++) { + const float32x4_t v = vmulq_n_f32(srcv[j], id); + const int32x4_t vi = vcvtnq_s32_f32(v); + + y[i].qs[4*j + 0] = vgetq_lane_s32(vi, 0); + y[i].qs[4*j + 1] = vgetq_lane_s32(vi, 1); + y[i].qs[4*j + 2] = vgetq_lane_s32(vi, 2); + y[i].qs[4*j + 3] = vgetq_lane_s32(vi, 3); + } + } +#elif defined(__wasm_simd128__) + for (int i = 0; i < nb; i++) { + v128_t srcv [8]; + v128_t asrcv[8]; + v128_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = wasm_v128_load(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = wasm_f32x4_abs(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = wasm_f32x4_max(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = wasm_f32x4_max(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = wasm_f32x4_max(amaxv[8*j], amaxv[8*j+4]); + + const float amax = MAX(MAX(wasm_f32x4_extract_lane(amaxv[0], 0), + wasm_f32x4_extract_lane(amaxv[0], 1)), + MAX(wasm_f32x4_extract_lane(amaxv[0], 2), + wasm_f32x4_extract_lane(amaxv[0], 3))); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < 8; j++) { + const v128_t v = wasm_f32x4_mul(srcv[j], wasm_f32x4_splat(id)); + const v128_t vi = wasm_i32x4_trunc_sat_f32x4(v); + + y[i].qs[4*j + 0] = wasm_i32x4_extract_lane(vi, 0); + y[i].qs[4*j + 1] = wasm_i32x4_extract_lane(vi, 1); + y[i].qs[4*j + 2] = wasm_i32x4_extract_lane(vi, 2); + y[i].qs[4*j + 3] = wasm_i32x4_extract_lane(vi, 3); + } + } +#elif defined(__AVX2__) || defined(__AVX__) + for (int i = 0; i < nb; i++) { + // Load elements into 4 AVX vectors + __m256 v0 = _mm256_loadu_ps( x ); + __m256 v1 = _mm256_loadu_ps( x + 8 ); + __m256 v2 = _mm256_loadu_ps( x + 16 ); + __m256 v3 = _mm256_loadu_ps( x + 24 ); + x += 32; + + // Compute max(abs(e)) for the block + const __m256 signBit = _mm256_set1_ps( -0.0f ); + __m256 maxAbs = _mm256_andnot_ps( signBit, v0 ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v1 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v2 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v3 ) ); + + __m128 max4 = _mm_max_ps( _mm256_extractf128_ps( maxAbs, 1 ), _mm256_castps256_ps128( maxAbs ) ); + max4 = _mm_max_ps( max4, _mm_movehl_ps( max4, max4 ) ); + max4 = _mm_max_ss( max4, _mm_movehdup_ps( max4 ) ); + const float maxScalar = _mm_cvtss_f32( max4 ); + + // Quantize these floats + const float d = maxScalar / 127.f; + y[i].d = GGML_FP32_TO_FP16(d); + const float id = ( maxScalar != 0.0f ) ? 127.f / maxScalar : 0.0f; + const __m256 mul = _mm256_set1_ps( id ); + + // Apply the multiplier + v0 = _mm256_mul_ps( v0, mul ); + v1 = _mm256_mul_ps( v1, mul ); + v2 = _mm256_mul_ps( v2, mul ); + v3 = _mm256_mul_ps( v3, mul ); + + // Round to nearest integer + v0 = _mm256_round_ps( v0, _MM_ROUND_NEAREST ); + v1 = _mm256_round_ps( v1, _MM_ROUND_NEAREST ); + v2 = _mm256_round_ps( v2, _MM_ROUND_NEAREST ); + v3 = _mm256_round_ps( v3, _MM_ROUND_NEAREST ); + + // Convert floats to integers + __m256i i0 = _mm256_cvtps_epi32( v0 ); + __m256i i1 = _mm256_cvtps_epi32( v1 ); + __m256i i2 = _mm256_cvtps_epi32( v2 ); + __m256i i3 = _mm256_cvtps_epi32( v3 ); + +#if defined(__AVX2__) + // Convert int32 to int16 + i0 = _mm256_packs_epi32( i0, i1 ); // 0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15 + i2 = _mm256_packs_epi32( i2, i3 ); // 16, 17, 18, 19, 24, 25, 26, 27, 20, 21, 22, 23, 28, 29, 30, 31 + // Convert int16 to int8 + i0 = _mm256_packs_epi16( i0, i2 ); // 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 + + // We got our precious signed bytes, but the order is now wrong + // These AVX2 pack instructions process 16-byte pieces independently + // The following instruction is fixing the order + const __m256i perm = _mm256_setr_epi32( 0, 4, 1, 5, 2, 6, 3, 7 ); + i0 = _mm256_permutevar8x32_epi32( i0, perm ); + + _mm256_storeu_si256((__m256i *)y[i].qs, i0); +#else + // Since we don't have in AVX some necessary functions, + // we split the registers in half and call AVX2 analogs from SSE + __m128i ni0 = _mm256_castsi256_si128( i0 ); + __m128i ni1 = _mm256_extractf128_si256( i0, 1); + __m128i ni2 = _mm256_castsi256_si128( i1 ); + __m128i ni3 = _mm256_extractf128_si256( i1, 1); + __m128i ni4 = _mm256_castsi256_si128( i2 ); + __m128i ni5 = _mm256_extractf128_si256( i2, 1); + __m128i ni6 = _mm256_castsi256_si128( i3 ); + __m128i ni7 = _mm256_extractf128_si256( i3, 1); + + // Convert int32 to int16 + ni0 = _mm_packs_epi32( ni0, ni1 ); + ni2 = _mm_packs_epi32( ni2, ni3 ); + ni4 = _mm_packs_epi32( ni4, ni5 ); + ni6 = _mm_packs_epi32( ni6, ni7 ); + // Convert int16 to int8 + ni0 = _mm_packs_epi16( ni0, ni2 ); + ni4 = _mm_packs_epi16( ni4, ni6 ); + + _mm_storeu_si128((__m128i *)(y[i].qs + 0), ni0); + _mm_storeu_si128((__m128i *)(y[i].qs + 16), ni4); +#endif + } +#elif defined(__riscv_v_intrinsic) + + size_t vl = __riscv_vsetvl_e32m4(QK8_0); + + for (int i = 0; i < nb; i++) { + // load elements + vfloat32m4_t v_x = __riscv_vle32_v_f32m4(x+i*QK8_0, vl); + + vfloat32m4_t vfabs = __riscv_vfabs_v_f32m4(v_x, vl); + vfloat32m1_t tmp = __riscv_vfmv_v_f_f32m1(0.0f, vl); + vfloat32m1_t vmax = __riscv_vfredmax_vs_f32m4_f32m1(vfabs, tmp, vl); + float amax = __riscv_vfmv_f_s_f32m1_f32(vmax); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + vfloat32m4_t x0 = __riscv_vfmul_vf_f32m4(v_x, id, vl); + + // convert to integer + vint16m2_t vi = __riscv_vfncvt_x_f_w_i16m2(x0, vl); + vint8m1_t vs = __riscv_vncvt_x_x_w_i8m1(vi, vl); + + // store result + __riscv_vse8_v_i8m1(y[i].qs , vs, vl); + } +#else + GGML_UNUSED(nb); + // scalar + quantize_row_q8_0_reference(x, y, k); +#endif +} + +// reference implementation for deterministic creation of model files +void quantize_row_q8_1_reference(const float * restrict x, block_q8_1 * restrict y, int64_t k) { + assert(QK8_1 == 32); + assert(k % QK8_1 == 0); + const int nb = k / QK8_1; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + + for (int j = 0; j < QK8_1; j++) { + const float v = x[i*QK8_1 + j]; + amax = MAX(amax, fabsf(v)); + } + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + int sum = 0; + + for (int j = 0; j < QK8_1/2; ++j) { + const float v0 = x[i*QK8_1 + j]*id; + const float v1 = x[i*QK8_1 + QK8_1/2 + j]*id; + + y[i].qs[ j] = roundf(v0); + y[i].qs[QK8_1/2 + j] = roundf(v1); + + sum += y[i].qs[ j]; + sum += y[i].qs[QK8_1/2 + j]; + } + + y[i].s = GGML_FP32_TO_FP16(sum*d); + } +} + +void quantize_row_q8_1(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK8_1 == 0); + const int nb = k / QK8_1; + + block_q8_1 * restrict y = vy; + +#if defined(__ARM_NEON) + for (int i = 0; i < nb; i++) { + float32x4_t srcv [8]; + float32x4_t asrcv[8]; + float32x4_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = vld1q_f32(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = vabsq_f32(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = vmaxq_f32(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = vmaxq_f32(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = vmaxq_f32(amaxv[8*j], amaxv[8*j+4]); + + const float amax = vmaxvq_f32(amaxv[0]); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + int32x4_t accv = vdupq_n_s32(0); + + for (int j = 0; j < 8; j++) { + const float32x4_t v = vmulq_n_f32(srcv[j], id); + const int32x4_t vi = vcvtnq_s32_f32(v); + + y[i].qs[4*j + 0] = vgetq_lane_s32(vi, 0); + y[i].qs[4*j + 1] = vgetq_lane_s32(vi, 1); + y[i].qs[4*j + 2] = vgetq_lane_s32(vi, 2); + y[i].qs[4*j + 3] = vgetq_lane_s32(vi, 3); + + accv = vaddq_s32(accv, vi); + } + + y[i].s = GGML_FP32_TO_FP16(d * vaddvq_s32(accv)); + } +#elif defined(__wasm_simd128__) + for (int i = 0; i < nb; i++) { + v128_t srcv [8]; + v128_t asrcv[8]; + v128_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = wasm_v128_load(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = wasm_f32x4_abs(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = wasm_f32x4_max(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = wasm_f32x4_max(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = wasm_f32x4_max(amaxv[8*j], amaxv[8*j+4]); + + const float amax = MAX(MAX(wasm_f32x4_extract_lane(amaxv[0], 0), + wasm_f32x4_extract_lane(amaxv[0], 1)), + MAX(wasm_f32x4_extract_lane(amaxv[0], 2), + wasm_f32x4_extract_lane(amaxv[0], 3))); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + v128_t accv = wasm_i32x4_splat(0); + + for (int j = 0; j < 8; j++) { + const v128_t v = wasm_f32x4_mul(srcv[j], wasm_f32x4_splat(id)); + const v128_t vi = wasm_i32x4_trunc_sat_f32x4(v); + + y[i].qs[4*j + 0] = wasm_i32x4_extract_lane(vi, 0); + y[i].qs[4*j + 1] = wasm_i32x4_extract_lane(vi, 1); + y[i].qs[4*j + 2] = wasm_i32x4_extract_lane(vi, 2); + y[i].qs[4*j + 3] = wasm_i32x4_extract_lane(vi, 3); + + accv = wasm_i32x4_add(accv, vi); + } + + y[i].s = GGML_FP32_TO_FP16( + d * (wasm_i32x4_extract_lane(accv, 0) + + wasm_i32x4_extract_lane(accv, 1) + + wasm_i32x4_extract_lane(accv, 2) + + wasm_i32x4_extract_lane(accv, 3))); + } +#elif defined(__AVX2__) || defined(__AVX__) + for (int i = 0; i < nb; i++) { + // Load elements into 4 AVX vectors + __m256 v0 = _mm256_loadu_ps( x ); + __m256 v1 = _mm256_loadu_ps( x + 8 ); + __m256 v2 = _mm256_loadu_ps( x + 16 ); + __m256 v3 = _mm256_loadu_ps( x + 24 ); + x += 32; + + // Compute max(abs(e)) for the block + const __m256 signBit = _mm256_set1_ps( -0.0f ); + __m256 maxAbs = _mm256_andnot_ps( signBit, v0 ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v1 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v2 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v3 ) ); + + __m128 max4 = _mm_max_ps( _mm256_extractf128_ps( maxAbs, 1 ), _mm256_castps256_ps128( maxAbs ) ); + max4 = _mm_max_ps( max4, _mm_movehl_ps( max4, max4 ) ); + max4 = _mm_max_ss( max4, _mm_movehdup_ps( max4 ) ); + const float maxScalar = _mm_cvtss_f32( max4 ); + + // Quantize these floats + const float d = maxScalar / 127.f; + y[i].d = GGML_FP32_TO_FP16(d); + const float id = ( maxScalar != 0.0f ) ? 127.f / maxScalar : 0.0f; + const __m256 mul = _mm256_set1_ps( id ); + + // Apply the multiplier + v0 = _mm256_mul_ps( v0, mul ); + v1 = _mm256_mul_ps( v1, mul ); + v2 = _mm256_mul_ps( v2, mul ); + v3 = _mm256_mul_ps( v3, mul ); + + // Round to nearest integer + v0 = _mm256_round_ps( v0, _MM_ROUND_NEAREST ); + v1 = _mm256_round_ps( v1, _MM_ROUND_NEAREST ); + v2 = _mm256_round_ps( v2, _MM_ROUND_NEAREST ); + v3 = _mm256_round_ps( v3, _MM_ROUND_NEAREST ); + + // Convert floats to integers + __m256i i0 = _mm256_cvtps_epi32( v0 ); + __m256i i1 = _mm256_cvtps_epi32( v1 ); + __m256i i2 = _mm256_cvtps_epi32( v2 ); + __m256i i3 = _mm256_cvtps_epi32( v3 ); + +#if defined(__AVX2__) + // Compute the sum of the quants and set y[i].s + y[i].s = GGML_FP32_TO_FP16(d * hsum_i32_8(_mm256_add_epi32(_mm256_add_epi32(i0, i1), _mm256_add_epi32(i2, i3)))); + + // Convert int32 to int16 + i0 = _mm256_packs_epi32( i0, i1 ); // 0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15 + i2 = _mm256_packs_epi32( i2, i3 ); // 16, 17, 18, 19, 24, 25, 26, 27, 20, 21, 22, 23, 28, 29, 30, 31 + // Convert int16 to int8 + i0 = _mm256_packs_epi16( i0, i2 ); // 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 + + // We got our precious signed bytes, but the order is now wrong + // These AVX2 pack instructions process 16-byte pieces independently + // The following instruction is fixing the order + const __m256i perm = _mm256_setr_epi32( 0, 4, 1, 5, 2, 6, 3, 7 ); + i0 = _mm256_permutevar8x32_epi32( i0, perm ); + + _mm256_storeu_si256((__m256i *)y[i].qs, i0); +#else + // Since we don't have in AVX some necessary functions, + // we split the registers in half and call AVX2 analogs from SSE + __m128i ni0 = _mm256_castsi256_si128( i0 ); + __m128i ni1 = _mm256_extractf128_si256( i0, 1); + __m128i ni2 = _mm256_castsi256_si128( i1 ); + __m128i ni3 = _mm256_extractf128_si256( i1, 1); + __m128i ni4 = _mm256_castsi256_si128( i2 ); + __m128i ni5 = _mm256_extractf128_si256( i2, 1); + __m128i ni6 = _mm256_castsi256_si128( i3 ); + __m128i ni7 = _mm256_extractf128_si256( i3, 1); + + // Compute the sum of the quants and set y[i].s + const __m128i s0 = _mm_add_epi32(_mm_add_epi32(ni0, ni1), _mm_add_epi32(ni2, ni3)); + const __m128i s1 = _mm_add_epi32(_mm_add_epi32(ni4, ni5), _mm_add_epi32(ni6, ni7)); + y[i].s = GGML_FP32_TO_FP16(d * hsum_i32_4(_mm_add_epi32(s0, s1))); + + // Convert int32 to int16 + ni0 = _mm_packs_epi32( ni0, ni1 ); + ni2 = _mm_packs_epi32( ni2, ni3 ); + ni4 = _mm_packs_epi32( ni4, ni5 ); + ni6 = _mm_packs_epi32( ni6, ni7 ); + // Convert int16 to int8 + ni0 = _mm_packs_epi16( ni0, ni2 ); + ni4 = _mm_packs_epi16( ni4, ni6 ); + + _mm_storeu_si128((__m128i *)(y[i].qs + 0), ni0); + _mm_storeu_si128((__m128i *)(y[i].qs + 16), ni4); +#endif + } +#elif defined(__riscv_v_intrinsic) + + size_t vl = __riscv_vsetvl_e32m4(QK8_1); + + for (int i = 0; i < nb; i++) { + // load elements + vfloat32m4_t v_x = __riscv_vle32_v_f32m4(x+i*QK8_1, vl); + + vfloat32m4_t vfabs = __riscv_vfabs_v_f32m4(v_x, vl); + vfloat32m1_t tmp = __riscv_vfmv_v_f_f32m1(0.0, vl); + vfloat32m1_t vmax = __riscv_vfredmax_vs_f32m4_f32m1(vfabs, tmp, vl); + float amax = __riscv_vfmv_f_s_f32m1_f32(vmax); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + vfloat32m4_t x0 = __riscv_vfmul_vf_f32m4(v_x, id, vl); + + // convert to integer + vint16m2_t vi = __riscv_vfncvt_x_f_w_i16m2(x0, vl); + vint8m1_t vs = __riscv_vncvt_x_x_w_i8m1(vi, vl); + + // store result + __riscv_vse8_v_i8m1(y[i].qs , vs, vl); + + // compute sum for y[i].s + vint16m1_t tmp2 = __riscv_vmv_v_x_i16m1(0, vl); + vint16m1_t vwrs = __riscv_vwredsum_vs_i8m1_i16m1(vs, tmp2, vl); + + // set y[i].s + int sum = __riscv_vmv_x_s_i16m1_i16(vwrs); + y[i].s = GGML_FP32_TO_FP16(sum*d); + } +#else + GGML_UNUSED(nb); + // scalar + quantize_row_q8_1_reference(x, y, k); +#endif +} + +void dequantize_row_q4_0(const block_q4_0 * restrict x, float * restrict y, int64_t k) { + static const int qk = QK4_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int j = 0; j < qk/2; ++j) { + const int x0 = (x[i].qs[j] & 0x0F) - 8; + const int x1 = (x[i].qs[j] >> 4) - 8; + + y[i*qk + j + 0 ] = x0*d; + y[i*qk + j + qk/2] = x1*d; + } + } +} + +void dequantize_row_q4_1(const block_q4_1 * restrict x, float * restrict y, int64_t k) { + static const int qk = QK4_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + const float m = GGML_FP16_TO_FP32(x[i].m); + + for (int j = 0; j < qk/2; ++j) { + const int x0 = (x[i].qs[j] & 0x0F); + const int x1 = (x[i].qs[j] >> 4); + + y[i*qk + j + 0 ] = x0*d + m; + y[i*qk + j + qk/2] = x1*d + m; + } + } +} + +void dequantize_row_q5_0(const block_q5_0 * restrict x, float * restrict y, int64_t k) { + static const int qk = QK5_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int32_t x0 = ((x[i].qs[j] & 0x0F) | xh_0) - 16; + const int32_t x1 = ((x[i].qs[j] >> 4) | xh_1) - 16; + + y[i*qk + j + 0 ] = x0*d; + y[i*qk + j + qk/2] = x1*d; + } + } +} + +void dequantize_row_q5_1(const block_q5_1 * restrict x, float * restrict y, int64_t k) { + static const int qk = QK5_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + const float m = GGML_FP16_TO_FP32(x[i].m); + + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int x0 = (x[i].qs[j] & 0x0F) | xh_0; + const int x1 = (x[i].qs[j] >> 4) | xh_1; + + y[i*qk + j + 0 ] = x0*d + m; + y[i*qk + j + qk/2] = x1*d + m; + } + } +} + +void dequantize_row_q8_0(const block_q8_0 * restrict x, float * restrict y, int64_t k) { + static const int qk = QK8_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int j = 0; j < qk; ++j) { + y[i*qk + j] = x[i].qs[j]*d; + } + } +} + +// +// 2-6 bit quantization in super-blocks +// + +// +// ===================== Helper functions +// +static inline int nearest_int(float fval) { + assert(fval <= 4194303.f); + float val = fval + 12582912.f; + int i; memcpy(&i, &val, sizeof(int)); + return (i & 0x007fffff) - 0x00400000; +} + +static float make_qx_quants(int n, int nmax, const float * restrict x, int8_t * restrict L, int rmse_type, + const float * restrict qw) { + float max = 0; + float amax = 0; + for (int i = 0; i < n; ++i) { + float ax = fabsf(x[i]); + if (ax > amax) { amax = ax; max = x[i]; } + } + if (amax < 1e-30f) { // all zero + for (int i = 0; i < n; ++i) { + L[i] = 0; + } + return 0.f; + } + float iscale = -nmax / max; + if (rmse_type == 0) { + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + L[i] = nmax + MAX(-nmax, MIN(nmax-1, l)); + } + return 1/iscale; + } + bool return_early = false; + if (rmse_type < 0) { + rmse_type = -rmse_type; + return_early = true; + } + float sumlx = 0; + float suml2 = 0; +#ifdef HAVE_BUGGY_APPLE_LINKER + // use 'volatile' to prevent unroll and work around a bug in Apple ld64 1015.7 + for (volatile int i = 0; i < n; ++i) { +#else + for (int i = 0; i < n; ++i) { +#endif + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l + nmax; + float w = qw ? qw[i] : rmse_type == 1 ? x[i] * x[i] : rmse_type == 2 ? 1 : rmse_type == 3 ? fabsf(x[i]) : sqrtf(fabsf(x[i])); + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + float scale = sumlx/suml2; + if (return_early) return suml2 > 0 ? 0.5f*(scale + 1/iscale) : 1/iscale; + float best = scale * sumlx; + for (int is = -9; is <= 9; ++is) { + if (is == 0) { + continue; + } + iscale = -(nmax + 0.1f*is) / max; + sumlx = suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + float w = qw ? qw[i] : rmse_type == 1 ? x[i] * x[i] : rmse_type == 2 ? 1 : rmse_type == 3 ? fabsf(x[i]) : sqrtf(fabsf(x[i])); + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + if (suml2 > 0 && sumlx*sumlx > best*suml2) { + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + L[i] = nmax + MAX(-nmax, MIN(nmax-1, l)); + } + scale = sumlx/suml2; best = scale*sumlx; + } + } + return scale; +} + +static float make_q3_quants(int n, int nmax, const float * restrict x, int8_t * restrict L, bool do_rmse) { + float max = 0; + float amax = 0; + for (int i = 0; i < n; ++i) { + float ax = fabsf(x[i]); + if (ax > amax) { amax = ax; max = x[i]; } + } + if (!amax) { // all zero + for (int i = 0; i < n; ++i) { L[i] = 0; } + return 0.f; + } + float iscale = -nmax / max; + if (do_rmse) { + float sumlx = 0; + float suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l; + float w = x[i]*x[i]; + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + for (int itry = 0; itry < 5; ++itry) { + int n_changed = 0; + for (int i = 0; i < n; ++i) { + float w = x[i]*x[i]; + float slx = sumlx - w*x[i]*L[i]; + if (slx > 0) { + float sl2 = suml2 - w*L[i]*L[i]; + int new_l = nearest_int(x[i] * sl2 / slx); + new_l = MAX(-nmax, MIN(nmax-1, new_l)); + if (new_l != L[i]) { + slx += w*x[i]*new_l; + sl2 += w*new_l*new_l; + if (sl2 > 0 && slx*slx*suml2 > sumlx*sumlx*sl2) { + L[i] = new_l; sumlx = slx; suml2 = sl2; + ++n_changed; + } + } + } + } + if (!n_changed) { + break; + } + } + for (int i = 0; i < n; ++i) { + L[i] += nmax; + } + return sumlx / suml2; + } + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l + nmax; + } + return 1/iscale; +} + +static float make_qkx1_quants(int n, int nmax, const float * restrict x, uint8_t * restrict L, float * restrict the_min, + int ntry, float alpha) { + float min = x[0]; + float max = x[0]; + for (int i = 1; i < n; ++i) { + if (x[i] < min) min = x[i]; + if (x[i] > max) max = x[i]; + } + if (max == min) { + for (int i = 0; i < n; ++i) L[i] = 0; + *the_min = 0; + return 0.f; + } + if (min > 0) min = 0; + float iscale = nmax/(max - min); + float scale = 1/iscale; + for (int itry = 0; itry < ntry; ++itry) { + float sumlx = 0; int suml2 = 0; + bool did_change = false; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + l = MAX(0, MIN(nmax, l)); + if (l != L[i]) { + L[i] = l; + did_change = true; + } + sumlx += (x[i] - min)*l; + suml2 += l*l; + } + scale = sumlx/suml2; + float sum = 0; + for (int i = 0; i < n; ++i) { + sum += x[i] - scale*L[i]; + } + min = alpha*min + (1 - alpha)*sum/n; + if (min > 0) min = 0; + iscale = 1/scale; + if (!did_change) break; + } + *the_min = -min; + return scale; +} + +static float make_qkx2_quants(int n, int nmax, const float * restrict x, const float * restrict weights, + uint8_t * restrict L, float * restrict the_min, uint8_t * restrict Laux, + float rmin, float rdelta, int nstep, bool use_mad) { + float min = x[0]; + float max = x[0]; + float sum_w = weights[0]; + float sum_x = sum_w * x[0]; +#ifdef HAVE_BUGGY_APPLE_LINKER + // use 'volatile' to prevent unroll and work around a bug in Apple ld64 1015.7 + for (volatile int i = 1; i < n; ++i) { +#else + for (int i = 1; i < n; ++i) { +#endif + if (x[i] < min) min = x[i]; + if (x[i] > max) max = x[i]; + float w = weights[i]; + sum_w += w; + sum_x += w * x[i]; + } + if (min > 0) min = 0; + if (max == min) { + for (int i = 0; i < n; ++i) L[i] = 0; + *the_min = -min; + return 0.f; + } + float iscale = nmax/(max - min); + float scale = 1/iscale; + float best_mad = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + L[i] = MAX(0, MIN(nmax, l)); + float diff = scale * L[i] + min - x[i]; + diff = use_mad ? fabsf(diff) : diff * diff; + float w = weights[i]; + best_mad += w * diff; + } + if (nstep < 1) { + *the_min = -min; + return scale; + } + for (int is = 0; is <= nstep; ++is) { + iscale = (rmin + rdelta*is + nmax)/(max - min); + float sum_l = 0, sum_l2 = 0, sum_xl = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + l = MAX(0, MIN(nmax, l)); + Laux[i] = l; + float w = weights[i]; + sum_l += w*l; + sum_l2 += w*l*l; + sum_xl += w*l*x[i]; + } + float D = sum_w * sum_l2 - sum_l * sum_l; + if (D > 0) { + float this_scale = (sum_w * sum_xl - sum_x * sum_l)/D; + float this_min = (sum_l2 * sum_x - sum_l * sum_xl)/D; + if (this_min > 0) { + this_min = 0; + this_scale = sum_xl / sum_l2; + } + float mad = 0; + for (int i = 0; i < n; ++i) { + float diff = this_scale * Laux[i] + this_min - x[i]; + diff = use_mad ? fabsf(diff) : diff * diff; + float w = weights[i]; + mad += w * diff; + } + if (mad < best_mad) { + for (int i = 0; i < n; ++i) { + L[i] = Laux[i]; + } + best_mad = mad; + scale = this_scale; + min = this_min; + } + } + } + *the_min = -min; + return scale; +} + +#if QK_K == 256 +static inline void get_scale_min_k4(int j, const uint8_t * restrict q, uint8_t * restrict d, uint8_t * restrict m) { + if (j < 4) { + *d = q[j] & 63; *m = q[j + 4] & 63; + } else { + *d = (q[j+4] & 0xF) | ((q[j-4] >> 6) << 4); + *m = (q[j+4] >> 4) | ((q[j-0] >> 6) << 4); + } +} +#endif + +//========================- 2-bit (de)-quantization + +void quantize_row_q2_K_reference(const float * restrict x, block_q2_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[16]; + float weights[16]; + float mins[QK_K/16]; + float scales[QK_K/16]; + + const float q4scale = 15.f; + + for (int i = 0; i < nb; i++) { + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 16; ++l) weights[l] = fabsf(x[16*j + l]); + scales[j] = make_qkx2_quants(16, 3, x + 16*j, weights, L + 16*j, &mins[j], Laux, -0.5f, 0.1f, 15, true); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + + if (max_scale > 0) { + float iscale = q4scale/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*scales[j]); + y[i].scales[j] = l; + } + y[i].d = GGML_FP32_TO_FP16(max_scale/q4scale); + } else { + for (int j = 0; j < QK_K/16; ++j) y[i].scales[j] = 0; + y[i].d = GGML_FP32_TO_FP16(0.f); + } + if (max_min > 0) { + float iscale = q4scale/max_min; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*mins[j]); + y[i].scales[j] |= (l << 4); + } + y[i].dmin = GGML_FP32_TO_FP16(max_min/q4scale); + } else { + y[i].dmin = GGML_FP32_TO_FP16(0.f); + } + for (int j = 0; j < QK_K/16; ++j) { + const float d = GGML_FP16_TO_FP32(y[i].d) * (y[i].scales[j] & 0xF); + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * (y[i].scales[j] >> 4); + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int((x[16*j + ii] + dm)/d); + l = MAX(0, MIN(3, l)); + L[16*j + ii] = l; + } + } + +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } +#else + for (int l = 0; l < 16; ++l) { + y[i].qs[l] = L[l] | (L[l + 16] << 2) | (L[l + 32] << 4) | (L[l + 48] << 6); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q2_K(const block_q2_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * q = x[i].qs; + +#if QK_K == 256 + int is = 0; + float dl, ml; + for (int n = 0; n < QK_K; n += 128) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + + uint8_t sc = x[i].scales[is++]; + dl = d * (sc & 0xF); ml = min * (sc >> 4); + for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l] >> shift) & 3)) - ml; + + sc = x[i].scales[is++]; + dl = d * (sc & 0xF); ml = min * (sc >> 4); + for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3)) - ml; + + shift += 2; + } + q += 32; + } +#else + float dl1 = d * (x[i].scales[0] & 0xF), ml1 = min * (x[i].scales[0] >> 4); + float dl2 = d * (x[i].scales[1] & 0xF), ml2 = min * (x[i].scales[1] >> 4); + float dl3 = d * (x[i].scales[2] & 0xF), ml3 = min * (x[i].scales[2] >> 4); + float dl4 = d * (x[i].scales[3] & 0xF), ml4 = min * (x[i].scales[3] >> 4); + for (int l = 0; l < 16; ++l) { + y[l+ 0] = dl1 * ((int8_t)((q[l] >> 0) & 3)) - ml1; + y[l+16] = dl2 * ((int8_t)((q[l] >> 2) & 3)) - ml2; + y[l+32] = dl3 * ((int8_t)((q[l] >> 4) & 3)) - ml3; + y[l+48] = dl4 * ((int8_t)((q[l] >> 6) & 3)) - ml4; + } + y += QK_K; +#endif + } +} + +void quantize_row_q2_K(const float * restrict x, void * restrict vy, int64_t k) { + quantize_row_q2_K_reference(x, vy, k); +} + +static float make_qkx3_quants(int n, int nmax, const float * restrict x, const float * restrict weights, + uint8_t * restrict L, float * restrict the_min, uint8_t * restrict Laux, + float rmin, float rdelta, int nstep, bool use_mad) { + float min = x[0]; + float max = x[0]; + float sum_w = weights ? weights[0] : x[0]*x[0]; + float sum_x = sum_w * x[0]; +#ifdef HAVE_BUGGY_APPLE_LINKER + // use 'volatile' to prevent unroll and work around a bug in Apple ld64 1015.7 + for (volatile int i = 1; i < n; ++i) { +#else + for (int i = 1; i < n; ++i) { +#endif + if (x[i] < min) min = x[i]; + if (x[i] > max) max = x[i]; + float w = weights ? weights[i] : x[i]*x[i]; + sum_w += w; + sum_x += w * x[i]; + } + if (min > 0) { + min = 0; + } + if (max <= min) { + memset(L, 0, n); + *the_min = -min; + return 0.f; + } + float iscale = nmax/(max - min); + float scale = 1/iscale; + float best_mad = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + L[i] = MAX(0, MIN(nmax, l)); + float diff = scale * L[i] + min - x[i]; + diff = use_mad ? fabsf(diff) : diff*diff; + float w = weights ? weights[i] : x[i]*x[i]; + best_mad += w * diff; + } + if (nstep < 1) { + *the_min = -min; + return scale; + } + for (int is = 0; is <= nstep; ++is) { + iscale = (rmin + rdelta*is + nmax)/(max - min); + float sum_l = 0, sum_l2 = 0, sum_xl = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + l = MAX(0, MIN(nmax, l)); + Laux[i] = l; + float w = weights ? weights[i] : x[i]*x[i]; + sum_l += w*l; + sum_l2 += w*l*l; + sum_xl += w*l*x[i]; + } + float D = sum_w * sum_l2 - sum_l * sum_l; + if (D > 0) { + float this_scale = (sum_w * sum_xl - sum_x * sum_l)/D; + float this_min = (sum_l2 * sum_x - sum_l * sum_xl)/D; + if (this_min > 0) { + this_min = 0; + this_scale = sum_xl / sum_l2; + } + float mad = 0; + for (int i = 0; i < n; ++i) { + float diff = this_scale * Laux[i] + this_min - x[i]; + diff = use_mad ? fabsf(diff) : diff*diff; + float w = weights ? weights[i] : x[i]*x[i]; + mad += w * diff; + } + if (mad < best_mad) { + for (int i = 0; i < n; ++i) { + L[i] = Laux[i]; + } + best_mad = mad; + scale = this_scale; + min = this_min; + } + } + } + *the_min = -min; + return scale; +} + +static float make_qp_quants(int n, int nmax, const float * restrict x, uint8_t * restrict L, const float * quant_weights) { + float max = 0; + for (int i = 0; i < n; ++i) { + max = MAX(max, x[i]); + } + if (!max) { // all zero + for (int i = 0; i < n; ++i) { L[i] = 0; } + return 0.f; + } + float iscale = nmax / max; + for (int i = 0; i < n; ++i) { + L[i] = nearest_int(iscale * x[i]); + } + float scale = 1/iscale; + float best_mse = 0; + for (int i = 0; i < n; ++i) { + float diff = x[i] - scale*L[i]; + float w = quant_weights[i]; + best_mse += w*diff*diff; + } + for (int is = -4; is <= 4; ++is) { + if (is == 0) continue; + float iscale_is = (0.1f*is + nmax)/max; + float scale_is = 1/iscale_is; + float mse = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale_is*x[i]); + l = MIN(nmax, l); + float diff = x[i] - scale_is*l; + float w = quant_weights[i]; + mse += w*diff*diff; + } + if (mse < best_mse) { + best_mse = mse; + iscale = iscale_is; + } + } + float sumlx = 0; + float suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MIN(nmax, l); + L[i] = l; + float w = quant_weights[i]; + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + for (int itry = 0; itry < 5; ++itry) { + int n_changed = 0; + for (int i = 0; i < n; ++i) { + float w = quant_weights[i]; + float slx = sumlx - w*x[i]*L[i]; + float sl2 = suml2 - w*L[i]*L[i]; + if (slx > 0 && sl2 > 0) { + int new_l = nearest_int(x[i] * sl2 / slx); + new_l = MIN(nmax, new_l); + if (new_l != L[i]) { + slx += w*x[i]*new_l; + sl2 += w*new_l*new_l; + if (slx*slx*suml2 > sumlx*sumlx*sl2) { + L[i] = new_l; sumlx = slx; suml2 = sl2; + ++n_changed; + } + } + } + } + if (!n_changed) { + break; + } + } + return sumlx / suml2; +} + +static void quantize_row_q2_K_impl(const float * restrict x, block_q2_K * restrict y, int k, const float * restrict quant_weights) { + GGML_ASSERT(quant_weights); + assert(k % QK_K == 0); + const int nb = k / QK_K; + const bool requantize = true; + + uint8_t L[QK_K]; + uint8_t Laux[16]; + float mins[QK_K/16]; + float scales[QK_K/16]; + float sw[QK_K/16]; + float weight[16]; + uint8_t Ls[QK_K/16], Lm[QK_K/16]; + + for (int i = 0; i < nb; i++) { + memset(sw, 0, QK_K/16*sizeof(float)); + float sumx2 = 0; + for (int j = 0; j < QK_K; ++j) sumx2 += x[j]*x[j]; + float sigma2 = sumx2/QK_K; + for (int j = 0; j < QK_K/16; ++j) { + const float * restrict qw = quant_weights + QK_K * i + 16*j; + for (int l = 0; l < 16; ++l) weight[l] = qw[l] * sqrtf(sigma2 + x[16*j + l]*x[16*j + l]); + for (int l = 0; l < QK_K/16; ++l) sw[j] += weight[l]; + scales[j] = make_qkx3_quants(16, 3, x + 16*j, weight, L + 16*j, &mins[j], Laux, -0.9f, 0.05f, 36, false); + } + + float dm, mm; +#if QK_K == 64 + float max_scale = 0, max_min = 0; + for (int j = 0; j < QK_K/16; ++j) { + max_scale = MAX(max_scale, scales[j]); + max_min = MAX(max_min, mins[j]); + } + dm = max_scale/15; + mm = max_min/15; + if (max_scale) { + float id = 1/dm; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(id*scales[j]); + Ls[j] = MAX(0, MIN(15, l)); + } + } else { + memset(Ls, 0, QK_K/16); + } + if (max_min) { + float id = 1/mm; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(id*mins[j]); + Lm[j] = MAX(0, MIN(15, l)); + } + } else { + memset(Lm, 0, QK_K/16); + } +#else + dm = make_qp_quants(QK_K/16, 15, scales, Ls, sw); + mm = make_qp_quants(QK_K/16, 15, mins, Lm, sw); +#endif + y[i].d = GGML_FP32_TO_FP16(dm); + y[i].dmin = GGML_FP32_TO_FP16(mm); + dm = GGML_FP16_TO_FP32(y[i].d); + mm = GGML_FP16_TO_FP32(y[i].dmin); + + for (int j = 0; j < QK_K/16; ++j) { + y[i].scales[j] = Ls[j] | (Lm[j] << 4); + } + + if (requantize) { + for (int j = 0; j < QK_K/16; ++j) { + const float d = dm * (y[i].scales[j] & 0xF); + if (!d) continue; + const float m = mm * (y[i].scales[j] >> 4); + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int((x[16*j + ii] + m)/d); + l = MAX(0, MIN(3, l)); + L[16*j + ii] = l; + } + } + } + +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } +#else + for (int l = 0; l < 16; ++l) { + y[i].qs[l] = L[l] | (L[l + 16] << 2) | (L[l + 32] << 4) | (L[l + 48] << 6); + } +#endif + + x += QK_K; + + } +} + +size_t quantize_q2_K(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + size_t row_size = ggml_row_size(GGML_TYPE_Q2_K, n_per_row); + if (!quant_weights) { + quantize_row_q2_K_reference(src, dst, (int64_t)nrow*n_per_row); + } + else { + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q2_K_impl(src, (block_q2_K*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + } + return nrow * row_size; +} + +//========================= 3-bit (de)-quantization + +void quantize_row_q3_K_reference(const float * restrict x, block_q3_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + int8_t L[QK_K]; + float scales[QK_K / 16]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; + float amax = 0; + for (int j = 0; j < QK_K/16; ++j) { + scales[j] = make_q3_quants(16, 4, x + 16*j, L + 16*j, true); + float scale = fabsf(scales[j]); + if (scale > amax) { + amax = scale; max_scale = scales[j]; + } + } + +#if QK_K == 256 + memset(y[i].scales, 0, 12); + if (max_scale) { + float iscale = -32.f/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int8_t l = nearest_int(iscale*scales[j]); + l = MAX(-32, MIN(31, l)) + 32; + if (j < 8) { + y[i].scales[j] = l & 0xF; + } else { + y[i].scales[j-8] |= ((l & 0xF) << 4); + } + l >>= 4; + y[i].scales[j%4 + 8] |= (l << (2*(j/4))); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + } else { + y[i].d = GGML_FP32_TO_FP16(0.f); + } + + int8_t sc; + for (int j = 0; j < QK_K/16; ++j) { + sc = j < 8 ? y[i].scales[j] & 0xF : y[i].scales[j-8] >> 4; + sc = (sc | (((y[i].scales[8 + j%4] >> (2*(j/4))) & 3) << 4)) - 32; + float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-4, MIN(3, l)); + L[16*j + ii] = l + 4; + } + } +#else + if (max_scale) { + float iscale = -8.f/max_scale; + for (int j = 0; j < QK_K/16; j+=2) { + int l1 = nearest_int(iscale*scales[j]); + l1 = 8 + MAX(-8, MIN(7, l1)); + int l2 = nearest_int(iscale*scales[j+1]); + l2 = 8 + MAX(-8, MIN(7, l2)); + y[i].scales[j/2] = l1 | (l2 << 4); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + } else { + for (int j = 0; j < QK_K/16; j+=2) { + y[i].scales[j/2] = 0; + } + y[i].d = GGML_FP32_TO_FP16(0.f); + } + for (int j = 0; j < QK_K/16; ++j) { + int s = j%2 == 0 ? y[i].scales[j/2] & 0xF : y[i].scales[j/2] >> 4; + float d = GGML_FP16_TO_FP32(y[i].d) * (s - 8); + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-4, MIN(3, l)); + L[16*j + ii] = l + 4; + } + } +#endif + + memset(y[i].hmask, 0, QK_K/8); + // We put the high-bit for the 1st 8 quants into bit 0, the next 8 into bit 1, etc. + int m = 0; + uint8_t hm = 1; + for (int j = 0; j < QK_K; ++j) { + if (L[j] > 3) { + y[i].hmask[m] |= hm; + L[j] -= 4; + } + if (++m == QK_K/8) { + m = 0; hm <<= 1; + } + } +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } +#else + for (int l = 0; l < 16; ++l) { + y[i].qs[l] = L[l] | (L[l + 16] << 2) | (L[l + 32] << 4) | (L[l + 48] << 6); + } +#endif + + x += QK_K; + } +} + +#if QK_K == 256 +void dequantize_row_q3_K(const block_q3_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + const uint32_t kmask1 = 0x03030303; + const uint32_t kmask2 = 0x0f0f0f0f; + + uint32_t aux[4]; + const int8_t * scales = (const int8_t*)aux; + + for (int i = 0; i < nb; i++) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + uint8_t m = 1; + + memcpy(aux, x[i].scales, 12); + uint32_t tmp = aux[2]; + aux[2] = ((aux[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4); + aux[3] = ((aux[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4); + aux[0] = (aux[0] & kmask2) | (((tmp >> 0) & kmask1) << 4); + aux[1] = (aux[1] & kmask2) | (((tmp >> 2) & kmask1) << 4); + + int is = 0; + float dl; + for (int n = 0; n < QK_K; n += 128) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + + dl = d_all * (scales[is++] - 32); + for (int l = 0; l < 16; ++l) { + *y++ = dl * ((int8_t)((q[l+ 0] >> shift) & 3) - ((hm[l+ 0] & m) ? 0 : 4)); + } + + dl = d_all * (scales[is++] - 32); + for (int l = 0; l < 16; ++l) { + *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3) - ((hm[l+16] & m) ? 0 : 4)); + } + + shift += 2; + m <<= 1; + } + q += 32; + } + + } +} +#else +void dequantize_row_q3_K(const block_q3_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + assert(QK_K == 64); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + + const float d1 = d_all * ((x[i].scales[0] & 0xF) - 8); + const float d2 = d_all * ((x[i].scales[0] >> 4) - 8); + const float d3 = d_all * ((x[i].scales[1] & 0xF) - 8); + const float d4 = d_all * ((x[i].scales[1] >> 4) - 8); + + for (int l=0; l<8; ++l) { + uint8_t h = hm[l]; + y[l+ 0] = d1 * ((int8_t)((q[l+0] >> 0) & 3) - ((h & 0x01) ? 0 : 4)); + y[l+ 8] = d1 * ((int8_t)((q[l+8] >> 0) & 3) - ((h & 0x02) ? 0 : 4)); + y[l+16] = d2 * ((int8_t)((q[l+0] >> 2) & 3) - ((h & 0x04) ? 0 : 4)); + y[l+24] = d2 * ((int8_t)((q[l+8] >> 2) & 3) - ((h & 0x08) ? 0 : 4)); + y[l+32] = d3 * ((int8_t)((q[l+0] >> 4) & 3) - ((h & 0x10) ? 0 : 4)); + y[l+40] = d3 * ((int8_t)((q[l+8] >> 4) & 3) - ((h & 0x20) ? 0 : 4)); + y[l+48] = d4 * ((int8_t)((q[l+0] >> 6) & 3) - ((h & 0x40) ? 0 : 4)); + y[l+56] = d4 * ((int8_t)((q[l+8] >> 6) & 3) - ((h & 0x80) ? 0 : 4)); + } + y += QK_K; + } +} +#endif + +void quantize_row_q3_K(const float * restrict x, void * restrict vy, int64_t k) { + quantize_row_q3_K_reference(x, vy, k); +} + +static void quantize_row_q3_K_impl(const float * restrict x, block_q3_K * restrict y, int64_t n_per_row, const float * restrict quant_weights) { +#if QK_K != 256 + (void)quant_weights; + quantize_row_q3_K_reference(x, y, n_per_row); +#else + assert(n_per_row % QK_K == 0); + const int nb = n_per_row / QK_K; + + int8_t L[QK_K]; + float scales[QK_K / 16]; + float weight[16]; + float sw[QK_K / 16]; + int8_t Ls[QK_K / 16]; + + for (int i = 0; i < nb; i++) { + + float sumx2 = 0; + for (int j = 0; j < QK_K; ++j) sumx2 += x[j]*x[j]; + float sigma2 = 2*sumx2/QK_K; + + for (int j = 0; j < QK_K/16; ++j) { + if (quant_weights) { + const float * qw = quant_weights ? quant_weights + QK_K * i + 16*j : NULL; + for (int l = 0; l < 16; ++l) weight[l] = qw[l] * sqrtf(sigma2 + x[16*j+l]*x[16*j+l]); + } else { + for (int l = 0; l < 16; ++l) weight[l] = x[16*j+l]*x[16*j+l]; + } + float sumw = 0; + for (int l = 0; l < 16; ++l) sumw += weight[l]; + sw[j] = sumw; + + scales[j] = make_qx_quants(16, 4, x + 16*j, L + 16*j, 1, weight); + + } + + memset(y[i].scales, 0, 12); + + float d_block = make_qx_quants(QK_K/16, 32, scales, Ls, 1, sw); + for (int j = 0; j < QK_K/16; ++j) { + int l = Ls[j]; + if (j < 8) { + y[i].scales[j] = l & 0xF; + } else { + y[i].scales[j-8] |= ((l & 0xF) << 4); + } + l >>= 4; + y[i].scales[j%4 + 8] |= (l << (2*(j/4))); + } + y[i].d = GGML_FP32_TO_FP16(d_block); + + int8_t sc; + for (int j = 0; j < QK_K/16; ++j) { + sc = j < 8 ? y[i].scales[j] & 0xF : y[i].scales[j-8] >> 4; + sc = (sc | (((y[i].scales[8 + j%4] >> (2*(j/4))) & 3) << 4)) - 32; + float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-4, MIN(3, l)); + L[16*j + ii] = l + 4; + } + } + + memset(y[i].hmask, 0, QK_K/8); + // We put the high-bit for the 1st 8 quants into bit 0, the next 8 into bit 1, etc. + int m = 0; + uint8_t hm = 1; + for (int j = 0; j < QK_K; ++j) { + if (L[j] > 3) { + y[i].hmask[m] |= hm; + L[j] -= 4; + } + if (++m == QK_K/8) { + m = 0; hm <<= 1; + } + } + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } + + x += QK_K; + } +#endif +} + +size_t quantize_q3_K(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + size_t row_size = ggml_row_size(GGML_TYPE_Q3_K, n_per_row); + if (!quant_weights) { + quantize_row_q3_K_reference(src, dst, (int64_t)nrow*n_per_row); + } + else { + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q3_K_impl(src, (block_q3_K*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + } + return nrow * row_size; +} + +// ====================== 4-bit (de)-quantization + +void quantize_row_q4_K_reference(const float * restrict x, block_q4_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[32]; + float weights[32]; + float mins[QK_K/32]; + float scales[QK_K/32]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/32; ++j) { + //scales[j] = make_qkx1_quants(32, 15, x + 32*j, L + 32*j, &mins[j], 9, 0.5f); + float sum_x2 = 0; + for (int l = 0; l < 32; ++l) sum_x2 += x[32*j + l] * x[32*j + l]; + float av_x = sqrtf(sum_x2/32); + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + scales[j] = make_qkx2_quants(32, 15, x + 32*j, weights, L + 32*j, &mins[j], Laux, -1.f, 0.1f, 20, false); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + +#if QK_K == 256 + float inv_scale = max_scale > 0 ? 63.f/max_scale : 0.f; + float inv_min = max_min > 0 ? 63.f/max_min : 0.f; + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = nearest_int(inv_scale*scales[j]); + uint8_t lm = nearest_int(inv_min*mins[j]); + ls = MIN(63, ls); + lm = MIN(63, lm); + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(max_scale/63.f); + y[i].dmin = GGML_FP32_TO_FP16(max_min/63.f); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(15, l)); + L[32*j + ii] = l; + } + } +#else + const float s_factor = 15.f; + float inv_scale = max_scale > 0 ? s_factor/max_scale : 0.f; + float inv_min = max_min > 0 ? s_factor/max_min : 0.f; + int d1 = nearest_int(inv_scale*scales[0]); + int m1 = nearest_int(inv_min*mins[0]); + int d2 = nearest_int(inv_scale*scales[1]); + int m2 = nearest_int(inv_min*mins[1]); + y[i].scales[0] = d1 | (m1 << 4); + y[i].scales[1] = d2 | (m2 << 4); + y[i].d[0] = GGML_FP32_TO_FP16(max_scale/s_factor); + y[i].d[1] = GGML_FP32_TO_FP16(max_min/s_factor); + + float sumlx = 0; + int suml2 = 0; + for (int j = 0; j < QK_K/32; ++j) { + const uint8_t sd = y[i].scales[j] & 0xF; + const uint8_t sm = y[i].scales[j] >> 4; + const float d = GGML_FP16_TO_FP32(y[i].d[0]) * sd; + if (!d) continue; + const float m = GGML_FP16_TO_FP32(y[i].d[1]) * sm; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + m)/d); + l = MAX(0, MIN(15, l)); + L[32*j + ii] = l; + sumlx += (x[32*j + ii] + m)*l*sd; + suml2 += l*l*sd*sd; + } + } + if (suml2) { + y[i].d[0] = GGML_FP32_TO_FP16(sumlx/suml2); + } +#endif + uint8_t * q = y[i].qs; + for (int j = 0; j < QK_K; j += 64) { + for (int l = 0; l < 32; ++l) q[l] = L[j + l] | (L[j + l + 32] << 4); + q += 32; + } + + x += QK_K; + + } +} + +void dequantize_row_q4_K(const block_q4_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const uint8_t * q = x[i].qs; + +#if QK_K == 256 + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + int is = 0; + uint8_t sc, m; + for (int j = 0; j < QK_K; j += 64) { + get_scale_min_k4(is + 0, x[i].scales, &sc, &m); + const float d1 = d * sc; const float m1 = min * m; + get_scale_min_k4(is + 1, x[i].scales, &sc, &m); + const float d2 = d * sc; const float m2 = min * m; + for (int l = 0; l < 32; ++l) *y++ = d1 * (q[l] & 0xF) - m1; + for (int l = 0; l < 32; ++l) *y++ = d2 * (q[l] >> 4) - m2; + q += 32; is += 2; + } +#else + const float dall = GGML_FP16_TO_FP32(x[i].d[0]); + const float mall = GGML_FP16_TO_FP32(x[i].d[1]); + const float d1 = dall * (x[i].scales[0] & 0xF), m1 = mall * (x[i].scales[0] >> 4); + const float d2 = dall * (x[i].scales[1] & 0xF), m2 = mall * (x[i].scales[1] >> 4); + for (int l = 0; l < 32; ++l) { + y[l+ 0] = d1 * (q[l] & 0xF) - m1; + y[l+32] = d2 * (q[l] >> 4) - m2; + } + y += QK_K; +#endif + + } +} + +void quantize_row_q4_K(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_q4_K * restrict y = vy; + quantize_row_q4_K_reference(x, y, k); +} + +static void quantize_row_q4_K_impl(const float * restrict x, block_q4_K * restrict y, int64_t n_per_row, const float * quant_weights) { +#if QK_K != 256 + (void)quant_weights; + quantize_row_q4_K_reference(x, y, n_per_row); +#else + assert(n_per_row % QK_K == 0); + const int64_t nb = n_per_row / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[32]; + uint8_t Ls[QK_K/32]; + uint8_t Lm[QK_K/32]; + float weights[32]; + float sw[QK_K/32]; + float mins[QK_K/32]; + float scales[QK_K/32]; + + for (int i = 0; i < nb; i++) { + + float sum_x2 = 0; + for (int l = 0; l < QK_K; ++l) sum_x2 += x[l] * x[l]; + float sigma2 = 2*sum_x2/QK_K; + float av_x = sqrtf(sigma2); + + for (int j = 0; j < QK_K/32; ++j) { + if (quant_weights) { + const float * qw = quant_weights + QK_K*i + 32*j; + for (int l = 0; l < 32; ++l) weights[l] = qw[l] * sqrtf(sigma2 + x[32*j + l]*x[32*j + l]); + } else { + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + } + float sumw = 0; + for (int l = 0; l < 32; ++l) sumw += weights[l]; + sw[j] = sumw; + scales[j] = make_qkx3_quants(32, 15, x + 32*j, weights, L + 32*j, &mins[j], Laux, -0.9f, 0.05f, 36, false); + } + + float d_block = make_qp_quants(QK_K/32, 63, scales, Ls, sw); + float m_block = make_qp_quants(QK_K/32, 63, mins, Lm, sw); + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = Ls[j]; + uint8_t lm = Lm[j]; + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(d_block); + y[i].dmin = GGML_FP32_TO_FP16(m_block); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(15, l)); + L[32*j + ii] = l; + } + } + uint8_t * q = y[i].qs; + for (int j = 0; j < QK_K; j += 64) { + for (int l = 0; l < 32; ++l) q[l] = L[j + l] | (L[j + l + 32] << 4); + q += 32; + } + + x += QK_K; + + } +#endif +} + +size_t quantize_q4_K(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + size_t row_size = ggml_row_size(GGML_TYPE_Q4_K, n_per_row); + if (!quant_weights) { + quantize_row_q4_K_reference(src, dst, (int64_t)nrow*n_per_row); + } + else { + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q4_K_impl(src, (block_q4_K*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + } + return nrow * row_size; +} + +// ====================== 5-bit (de)-quantization + +void quantize_row_q5_K_reference(const float * restrict x, block_q5_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + +#if QK_K == 256 + uint8_t L[QK_K]; + float mins[QK_K/32]; + float scales[QK_K/32]; + float weights[32]; + uint8_t Laux[32]; +#else + int8_t L[QK_K]; + float scales[QK_K/16]; +#endif + + for (int i = 0; i < nb; i++) { + +#if QK_K == 256 + + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/32; ++j) { + //scales[j] = make_qkx1_quants(32, 31, x + 32*j, L + 32*j, &mins[j], 9, 0.5f); + float sum_x2 = 0; + for (int l = 0; l < 32; ++l) sum_x2 += x[32*j + l] * x[32*j + l]; + float av_x = sqrtf(sum_x2/32); + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + scales[j] = make_qkx2_quants(32, 31, x + 32*j, weights, L + 32*j, &mins[j], Laux, -0.5f, 0.1f, 15, false); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + + float inv_scale = max_scale > 0 ? 63.f/max_scale : 0.f; + float inv_min = max_min > 0 ? 63.f/max_min : 0.f; + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = nearest_int(inv_scale*scales[j]); + uint8_t lm = nearest_int(inv_min*mins[j]); + ls = MIN(63, ls); + lm = MIN(63, lm); + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(max_scale/63.f); + y[i].dmin = GGML_FP32_TO_FP16(max_min/63.f); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(31, l)); + L[32*j + ii] = l; + } + } + + uint8_t * restrict qh = y[i].qh; + uint8_t * restrict ql = y[i].qs; + memset(qh, 0, QK_K/8); + + uint8_t m1 = 1, m2 = 2; + for (int n = 0; n < QK_K; n += 64) { + for (int j = 0; j < 32; ++j) { + int l1 = L[n + j]; + if (l1 > 15) { + l1 -= 16; qh[j] |= m1; + } + int l2 = L[n + j + 32]; + if (l2 > 15) { + l2 -= 16; qh[j] |= m2; + } + ql[j] = l1 | (l2 << 4); + } + m1 <<= 2; m2 <<= 2; + ql += 32; + } +#else + float max_scale = 0, amax = 0; + for (int j = 0; j < QK_K/16; ++j) { + scales[j] = make_qx_quants(16, 16, x + 16*j, L + 16*j, 1, NULL); + float abs_scale = fabsf(scales[j]); + if (abs_scale > amax) { + amax = abs_scale; + max_scale = scales[j]; + } + } + + float iscale = -128.f/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*scales[j]); + y[i].scales[j] = MAX(-128, MIN(127, l)); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + + for (int j = 0; j < QK_K/16; ++j) { + const float d = GGML_FP16_TO_FP32(y[i].d) * y[i].scales[j]; + if (!d) continue; + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-16, MIN(15, l)); + L[16*j + ii] = l + 16; + } + } + + uint8_t * restrict qh = y[i].qh; + uint8_t * restrict ql = y[i].qs; + memset(qh, 0, QK_K/8); + + for (int j = 0; j < 32; ++j) { + int jm = j%8; + int is = j/8; + int l1 = L[j]; + if (l1 > 15) { + l1 -= 16; qh[jm] |= (1 << is); + } + int l2 = L[j + 32]; + if (l2 > 15) { + l2 -= 16; qh[jm] |= (1 << (4 + is)); + } + ql[j] = l1 | (l2 << 4); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q5_K(const block_q5_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const uint8_t * ql = x[i].qs; + const uint8_t * qh = x[i].qh; + +#if QK_K == 256 + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + int is = 0; + uint8_t sc, m; + uint8_t u1 = 1, u2 = 2; + for (int j = 0; j < QK_K; j += 64) { + get_scale_min_k4(is + 0, x[i].scales, &sc, &m); + const float d1 = d * sc; const float m1 = min * m; + get_scale_min_k4(is + 1, x[i].scales, &sc, &m); + const float d2 = d * sc; const float m2 = min * m; + for (int l = 0; l < 32; ++l) *y++ = d1 * ((ql[l] & 0xF) + (qh[l] & u1 ? 16 : 0)) - m1; + for (int l = 0; l < 32; ++l) *y++ = d2 * ((ql[l] >> 4) + (qh[l] & u2 ? 16 : 0)) - m2; + ql += 32; is += 2; + u1 <<= 2; u2 <<= 2; + } +#else + float d = GGML_FP16_TO_FP32(x[i].d); + const int8_t * restrict s = x[i].scales; + for (int l = 0; l < 8; ++l) { + y[l+ 0] = d * s[0] * ((ql[l+ 0] & 0xF) - (qh[l] & 0x01 ? 0 : 16)); + y[l+ 8] = d * s[0] * ((ql[l+ 8] & 0xF) - (qh[l] & 0x02 ? 0 : 16)); + y[l+16] = d * s[1] * ((ql[l+16] & 0xF) - (qh[l] & 0x04 ? 0 : 16)); + y[l+24] = d * s[1] * ((ql[l+24] & 0xF) - (qh[l] & 0x08 ? 0 : 16)); + y[l+32] = d * s[2] * ((ql[l+ 0] >> 4) - (qh[l] & 0x10 ? 0 : 16)); + y[l+40] = d * s[2] * ((ql[l+ 8] >> 4) - (qh[l] & 0x20 ? 0 : 16)); + y[l+48] = d * s[3] * ((ql[l+16] >> 4) - (qh[l] & 0x40 ? 0 : 16)); + y[l+56] = d * s[3] * ((ql[l+24] >> 4) - (qh[l] & 0x80 ? 0 : 16)); + } + y += QK_K; +#endif + } +} + +void quantize_row_q5_K(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_q5_K * restrict y = vy; + quantize_row_q5_K_reference(x, y, k); +} + +static void quantize_row_q5_K_impl(const float * restrict x, block_q5_K * restrict y, int64_t n_per_row, const float * quant_weights) { +#if QK_K != 256 + (void)quant_weights; + quantize_row_q5_K_reference(x, y, n_per_row); +#else + assert(n_per_row % QK_K == 0); + const int64_t nb = n_per_row / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[32]; + uint8_t Ls[QK_K/32]; + uint8_t Lm[QK_K/32]; + float mins[QK_K/32]; + float scales[QK_K/32]; + float sw[QK_K/32]; + float weights[32]; + + for (int i = 0; i < nb; i++) { + + float sum_x2 = 0; + for (int l = 0; l < QK_K; ++l) sum_x2 += x[l] * x[l]; + float sigma2 = 2*sum_x2/QK_K; + float av_x = sqrtf(sigma2); + + for (int j = 0; j < QK_K/32; ++j) { + if (quant_weights) { + const float * qw = quant_weights + QK_K*i + 32*j; + for (int l = 0; l < 32; ++l) weights[l] = qw[l] * sqrtf(sigma2 + x[32*j + l]*x[32*j + l]); + } else { + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + } + float sumw = 0; + for (int l = 0; l < 32; ++l) sumw += weights[l]; + sw[j] = sumw; + + scales[j] = make_qkx3_quants(32, 31, x + 32*j, weights, L + 32*j, &mins[j], Laux, -0.9f, 0.05f, 36, false); + } + + float d_block = make_qp_quants(QK_K/32, 63, scales, Ls, sw); + float m_block = make_qp_quants(QK_K/32, 63, mins, Lm, sw); + + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = Ls[j]; + uint8_t lm = Lm[j]; + ls = MIN(63, ls); + lm = MIN(63, lm); + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(d_block); + y[i].dmin = GGML_FP32_TO_FP16(m_block); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(31, l)); + L[32*j + ii] = l; + } + } + + uint8_t * restrict qh = y[i].qh; + uint8_t * restrict ql = y[i].qs; + memset(qh, 0, QK_K/8); + + uint8_t m1 = 1, m2 = 2; + for (int n = 0; n < QK_K; n += 64) { + for (int j = 0; j < 32; ++j) { + int l1 = L[n + j]; + if (l1 > 15) { + l1 -= 16; qh[j] |= m1; + } + int l2 = L[n + j + 32]; + if (l2 > 15) { + l2 -= 16; qh[j] |= m2; + } + ql[j] = l1 | (l2 << 4); + } + m1 <<= 2; m2 <<= 2; + ql += 32; + } + + x += QK_K; + + } +#endif +} + +size_t quantize_q5_K(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + size_t row_size = ggml_row_size(GGML_TYPE_Q5_K, n_per_row); + if (!quant_weights) { + quantize_row_q5_K_reference(src, dst, (int64_t)nrow*n_per_row); + } + else { + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q5_K_impl(src, (block_q5_K*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + } + return nrow * row_size; +} + +// ====================== 6-bit (de)-quantization + +void quantize_row_q6_K_reference(const float * restrict x, block_q6_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + int8_t L[QK_K]; + float scales[QK_K/16]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; + float max_abs_scale = 0; + + for (int ib = 0; ib < QK_K/16; ++ib) { + + const float scale = make_qx_quants(16, 32, x + 16*ib, L + 16*ib, 1, NULL); + scales[ib] = scale; + + const float abs_scale = fabsf(scale); + if (abs_scale > max_abs_scale) { + max_abs_scale = abs_scale; + max_scale = scale; + } + + } + + if (!max_abs_scale) { + memset(&y[i], 0, sizeof(block_q6_K)); + y[i].d = GGML_FP32_TO_FP16(0.f); + x += QK_K; + continue; + } + + float iscale = -128.f/max_scale; + y[i].d = GGML_FP32_TO_FP16(1/iscale); + for (int ib = 0; ib < QK_K/16; ++ib) { + y[i].scales[ib] = MIN(127, nearest_int(iscale*scales[ib])); + } + + for (int j = 0; j < QK_K/16; ++j) { + float d = GGML_FP16_TO_FP32(y[i].d) * y[i].scales[j]; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-32, MIN(31, l)); + L[16*j + ii] = l + 32; + } + } + + uint8_t * restrict ql = y[i].ql; + uint8_t * restrict qh = y[i].qh; +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + const uint8_t q1 = L[j + l + 0] & 0xF; + const uint8_t q2 = L[j + l + 32] & 0xF; + const uint8_t q3 = L[j + l + 64] & 0xF; + const uint8_t q4 = L[j + l + 96] & 0xF; + ql[l+ 0] = q1 | (q3 << 4); + ql[l+32] = q2 | (q4 << 4); + qh[l] = (L[j + l] >> 4) | ((L[j + l + 32] >> 4) << 2) | ((L[j + l + 64] >> 4) << 4) | ((L[j + l + 96] >> 4) << 6); + } + ql += 64; + qh += 32; + } +#else + for (int l = 0; l < 32; ++l) { + const uint8_t q1 = L[l + 0] & 0xF; + const uint8_t q2 = L[l + 32] & 0xF; + ql[l] = q1 | (q2 << 4); + } + for (int l = 0; l < 16; ++l) { + qh[l] = (L[l] >> 4) | ((L[l + 16] >> 4) << 2) | ((L[l + 32] >> 4) << 4) | ((L[l + 48] >> 4) << 6); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q6_K(const block_q6_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict ql = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict sc = x[i].scales; + +#if QK_K == 256 + for (int n = 0; n < QK_K; n += 128) { + for (int l = 0; l < 32; ++l) { + int is = l/16; + const int8_t q1 = (int8_t)((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + const int8_t q3 = (int8_t)((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + const int8_t q4 = (int8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + y[l + 0] = d * sc[is + 0] * q1; + y[l + 32] = d * sc[is + 2] * q2; + y[l + 64] = d * sc[is + 4] * q3; + y[l + 96] = d * sc[is + 6] * q4; + } + y += 128; + ql += 64; + qh += 32; + sc += 8; + } +#else + for (int l = 0; l < 16; ++l) { + const int8_t q1 = (int8_t)((ql[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + const int8_t q2 = (int8_t)((ql[l+16] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + const int8_t q3 = (int8_t)((ql[l+ 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + const int8_t q4 = (int8_t)((ql[l+16] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + y[l+ 0] = d * sc[0] * q1; + y[l+16] = d * sc[1] * q2; + y[l+32] = d * sc[2] * q3; + y[l+48] = d * sc[3] * q4; + } + y += 64; +#endif + + } +} + +void quantize_row_q6_K(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_q6_K * restrict y = vy; + quantize_row_q6_K_reference(x, y, k); +} + +static void quantize_row_q6_K_impl(const float * restrict x, block_q6_K * restrict y, int64_t n_per_row, const float * quant_weights) { +#if QK_K != 256 + (void)quant_weights; + quantize_row_q6_K_reference(x, y, n_per_row); +#else + assert(n_per_row % QK_K == 0); + const int64_t nb = n_per_row / QK_K; + + int8_t L[QK_K]; + float scales[QK_K/16]; + //float weights[16]; + + for (int i = 0; i < nb; i++) { + + //float sum_x2 = 0; + //for (int j = 0; j < QK_K; ++j) sum_x2 += x[j]*x[j]; + //float sigma2 = sum_x2/QK_K; + + float max_scale = 0; + float max_abs_scale = 0; + + for (int ib = 0; ib < QK_K/16; ++ib) { + + float scale; + if (quant_weights) { + const float * qw = quant_weights + QK_K*i + 16*ib; + //for (int j = 0; j < 16; ++j) weights[j] = qw[j] * sqrtf(sigma2 + x[16*ib + j]*x[16*ib + j]); + //scale = make_qx_quants(16, 32, x + 16*ib, L + 16*ib, 1, weights); + scale = make_qx_quants(16, 32, x + 16*ib, L + 16*ib, 1, qw); + } else { + scale = make_qx_quants(16, 32, x + 16*ib, L + 16*ib, 1, NULL); + } + scales[ib] = scale; + + const float abs_scale = fabsf(scale); + if (abs_scale > max_abs_scale) { + max_abs_scale = abs_scale; + max_scale = scale; + } + + } + + if (!max_abs_scale) { + memset(&y[i], 0, sizeof(block_q6_K)); + y[i].d = GGML_FP32_TO_FP16(0.f); + x += QK_K; + continue; + } + + float iscale = -128.f/max_scale; + y[i].d = GGML_FP32_TO_FP16(1/iscale); + for (int ib = 0; ib < QK_K/16; ++ib) { + y[i].scales[ib] = MIN(127, nearest_int(iscale*scales[ib])); + } + + for (int j = 0; j < QK_K/16; ++j) { + float d = GGML_FP16_TO_FP32(y[i].d) * y[i].scales[j]; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-32, MIN(31, l)); + L[16*j + ii] = l + 32; + } + } + + uint8_t * restrict ql = y[i].ql; + uint8_t * restrict qh = y[i].qh; + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + const uint8_t q1 = L[j + l + 0] & 0xF; + const uint8_t q2 = L[j + l + 32] & 0xF; + const uint8_t q3 = L[j + l + 64] & 0xF; + const uint8_t q4 = L[j + l + 96] & 0xF; + ql[l+ 0] = q1 | (q3 << 4); + ql[l+32] = q2 | (q4 << 4); + qh[l] = (L[j + l] >> 4) | ((L[j + l + 32] >> 4) << 2) | ((L[j + l + 64] >> 4) << 4) | ((L[j + l + 96] >> 4) << 6); + } + ql += 64; + qh += 32; + } + + x += QK_K; + + } +#endif +} + +size_t quantize_q6_K(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + size_t row_size = ggml_row_size(GGML_TYPE_Q6_K, n_per_row); + if (!quant_weights) { + quantize_row_q6_K_reference(src, dst, (int64_t)nrow*n_per_row); + } + else { + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q6_K_impl(src, (block_q6_K*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + } + return nrow * row_size; +} + +static void quantize_row_q4_0_impl(const float * restrict x, block_q4_0 * restrict y, int64_t n_per_row, const float * quant_weights) { + static_assert(QK4_0 == 32, "QK4_0 must be 32"); + + if (!quant_weights) { + quantize_row_q4_0_reference(x, y, n_per_row); + return; + } + + float weight[QK4_0]; + int8_t L[QK4_0]; + + float sum_x2 = 0; + for (int j = 0; j < n_per_row; ++j) sum_x2 += x[j]*x[j]; + float sigma2 = sum_x2/n_per_row; + + const int64_t nb = n_per_row/QK4_0; + for (int ib = 0; ib < nb; ++ib) { + const float * xb = x + QK4_0 * ib; + const float * qw = quant_weights + QK4_0 * ib; + for (int j = 0; j < QK4_0; ++j) weight[j] = qw[j] * sqrtf(sigma2 + xb[j]*xb[j]); + float d = make_qx_quants(QK4_0, 8, xb, L, 1, weight); + y[ib].d = GGML_FP32_TO_FP16(d); + for (int j = 0; j < 16; ++j) { + y[ib].qs[j] = L[j] | (L[j+16] << 4); + } + } +} + +size_t quantize_q4_0(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + if (!quant_weights) { + quantize_row_q4_0_reference(src, dst, (int64_t)nrow*n_per_row); + return nrow * ggml_row_size(GGML_TYPE_Q4_0, n_per_row); + } + size_t row_size = ggml_row_size(GGML_TYPE_Q4_0, n_per_row); + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q4_0_impl(src, (block_q4_0*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + return nrow * row_size; +} + +static void quantize_row_q4_1_impl(const float * restrict x, block_q4_1 * restrict y, int64_t n_per_row, const float * quant_weights) { + static_assert(QK4_1 == 32, "QK4_1 must be 32"); + + if (!quant_weights) { + quantize_row_q4_1_reference(x, y, n_per_row); + return; + } + + float weight[QK4_1]; + uint8_t L[QK4_1], Laux[QK4_1]; + + float sum_x2 = 0; + for (int j = 0; j < n_per_row; ++j) sum_x2 += x[j]*x[j]; + float sigma2 = sum_x2/n_per_row; + + const int64_t nb = n_per_row/QK4_1; + for (int ib = 0; ib < nb; ++ib) { + const float * xb = x + QK4_1 * ib; + const float * qw = quant_weights + QK4_1 * ib; + for (int j = 0; j < QK4_1; ++j) weight[j] = qw[j] * sqrtf(sigma2 + xb[j]*xb[j]); + float min; + float d = make_qkx3_quants(QK4_1, 15, xb, weight, L, &min, Laux, -0.9f, 0.05f, 36, false); + y[ib].d = GGML_FP32_TO_FP16(d); + y[ib].m = GGML_FP32_TO_FP16(-min); + for (int j = 0; j < 16; ++j) { + y[ib].qs[j] = L[j] | (L[j+16] << 4); + } + } +} + +size_t quantize_q4_1(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + if (!quant_weights) { + quantize_row_q4_1_reference(src, dst, (int64_t)nrow*n_per_row); + return nrow * ggml_row_size(GGML_TYPE_Q4_1, n_per_row); + } + size_t row_size = ggml_row_size(GGML_TYPE_Q4_1, n_per_row); + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q4_1_impl(src, (block_q4_1*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + return nrow * row_size; +} + +static void quantize_row_q5_0_impl(const float * restrict x, block_q5_0 * restrict y, int64_t n_per_row, const float * quant_weights) { + static_assert(QK5_0 == 32, "QK5_0 must be 32"); + + if (!quant_weights) { + quantize_row_q5_0_reference(x, y, n_per_row); + return; + } + + float weight[QK5_0]; + int8_t L[QK5_0]; + + float sum_x2 = 0; + for (int j = 0; j < n_per_row; ++j) sum_x2 += x[j]*x[j]; + float sigma2 = sum_x2/n_per_row; + + const int64_t nb = n_per_row/QK5_0; + for (int ib = 0; ib < nb; ++ib) { + const float * xb = x + QK5_0 * ib; + const float * qw = quant_weights + QK5_0 * ib; + for (int j = 0; j < QK5_0; ++j) weight[j] = qw[j] * sqrtf(sigma2 + xb[j]*xb[j]); + float d = make_qx_quants(QK5_0, 16, xb, L, 1, weight); + y[ib].d = GGML_FP32_TO_FP16(d); + + uint32_t qh = 0; + + for (int j = 0; j < 16; ++j) { + const uint8_t xi0 = L[j]; + const uint8_t xi1 = L[j+16]; + y[ib].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + QK5_0/2); + } + + memcpy(&y[ib].qh, &qh, sizeof(qh)); + } +} + +size_t quantize_q5_0(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + if (!quant_weights) { + quantize_row_q5_0_reference(src, dst, (int64_t)nrow*n_per_row); + return nrow * ggml_row_size(GGML_TYPE_Q5_0, n_per_row); + } + size_t row_size = ggml_row_size(GGML_TYPE_Q5_0, n_per_row); + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q5_0_impl(src, (block_q5_0*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + return nrow * row_size; +} + +static void quantize_row_q5_1_impl(const float * restrict x, block_q5_1 * restrict y, int64_t n_per_row, const float * quant_weights) { + static_assert(QK5_1 == 32, "QK5_1 must be 32"); + + if (!quant_weights) { + quantize_row_q5_1_reference(x, y, n_per_row); + return; + } + + float weight[QK5_1]; + uint8_t L[QK5_1], Laux[QK5_1]; + + float sum_x2 = 0; + for (int j = 0; j < n_per_row; ++j) sum_x2 += x[j]*x[j]; + float sigma2 = sum_x2/n_per_row; + + const int64_t nb = n_per_row/QK5_1; + for (int ib = 0; ib < nb; ++ib) { + const float * xb = x + QK5_1 * ib; + const float * qw = quant_weights + QK5_1 * ib; + for (int j = 0; j < QK5_1; ++j) weight[j] = qw[j] * sqrtf(sigma2 + xb[j]*xb[j]); + float min; + float d = make_qkx3_quants(QK5_1, 31, xb, weight, L, &min, Laux, -0.9f, 0.05f, 36, false); + y[ib].d = GGML_FP32_TO_FP16(d); + y[ib].m = GGML_FP32_TO_FP16(-min); + + uint32_t qh = 0; + for (int j = 0; j < 16; ++j) { + const uint8_t xi0 = L[j]; + const uint8_t xi1 = L[j+16]; + y[ib].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + QK5_0/2); + } + memcpy(&y[ib].qh, &qh, sizeof(qh)); + } +} + +size_t quantize_q5_1(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + if (!quant_weights) { + quantize_row_q5_1_reference(src, dst, (int64_t)nrow*n_per_row); + return nrow * ggml_row_size(GGML_TYPE_Q5_1, n_per_row); + } + size_t row_size = ggml_row_size(GGML_TYPE_Q5_1, n_per_row); + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_q5_1_impl(src, (block_q5_1*)qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += row_size; + } + return nrow * row_size; +} + +size_t quantize_q8_0(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + (void)quant_weights; // not used + const size_t row_size = ggml_row_size(GGML_TYPE_Q8_0, n_per_row); + quantize_row_q8_0_reference(src, dst, (int64_t)nrow*n_per_row); + return nrow * row_size; +} + +// ====================== "True" 2-bit (de)-quantization + +void dequantize_row_iq2_xxs(const block_iq2_xxs * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + uint32_t aux32[2]; + const uint8_t * aux8 = (const uint8_t *)aux32; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + memcpy(aux32, x[i].qs + 4*ib32, 2*sizeof(uint32_t)); + const float db = d * (0.5f + (aux32[1] >> 28)) * 0.25f; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2xxs_grid + aux8[l]); + const uint8_t signs = ksigns_iq2xs[(aux32[1] >> 7*l) & 127]; + for (int j = 0; j < 8; ++j) { + y[j] = db * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f); + } + y += 8; + } + } + } +} + +// ====================== 2.3125 bpw (de)-quantization + +void dequantize_row_iq2_xs(const block_iq2_xs * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + float db[2]; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + db[0] = d * (0.5f + (x[i].scales[ib32] & 0xf)) * 0.25f; + db[1] = d * (0.5f + (x[i].scales[ib32] >> 4)) * 0.25f; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2xs_grid + (x[i].qs[4*ib32 + l] & 511)); + const uint8_t signs = ksigns_iq2xs[x[i].qs[4*ib32 + l] >> 9]; + for (int j = 0; j < 8; ++j) { + y[j] = db[l/2] * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f); + } + y += 8; + } + } + } +} + +// ====================== 2.5625 bpw (de)-quantization + +void dequantize_row_iq2_s(const block_iq2_s * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + float db[2]; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint8_t * signs = qs + QK_K/8; + + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + db[0] = d * (0.5f + (x[i].scales[ib32] & 0xf)) * 0.25f; + db[1] = d * (0.5f + (x[i].scales[ib32] >> 4)) * 0.25f; + for (int l = 0; l < 4; ++l) { + const float dl = db[l/2]; + const uint8_t * grid = (const uint8_t *)(iq2s_grid + (qs[l] | (qh[ib32] << (8-2*l) & 0x300))); + for (int j = 0; j < 8; ++j) { + y[j] = dl * grid[j] * (signs[l] & kmask_iq2xs[j] ? -1.f : 1.f); + } + y += 8; + } + qs += 4; + signs += 4; + } + } +} + +// ====================== 3.0625 bpw (de)-quantization + +void dequantize_row_iq3_xxs(const block_iq3_xxs * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + uint32_t aux32; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const uint8_t * qs = x[i].qs; + const uint8_t * scales_and_signs = qs + QK_K/4; + + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + memcpy(&aux32, scales_and_signs + 4*ib32, sizeof(uint32_t)); + const float db = d * (0.5f + (aux32 >> 28)) * 0.5f; + for (int l = 0; l < 4; ++l) { + const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*l) & 127]; + const uint8_t * grid1 = (const uint8_t *)(iq3xxs_grid + qs[2*l+0]); + const uint8_t * grid2 = (const uint8_t *)(iq3xxs_grid + qs[2*l+1]); + for (int j = 0; j < 4; ++j) { + y[j+0] = db * grid1[j] * (signs & kmask_iq2xs[j+0] ? -1.f : 1.f); + y[j+4] = db * grid2[j] * (signs & kmask_iq2xs[j+4] ? -1.f : 1.f); + } + y += 8; + } + qs += 8; + } + } +} + +// ====================== 3.3125 bpw (de)-quantization + +void dequantize_row_iq3_s(const block_iq3_s * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint8_t * signs = x[i].signs; + + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const float db1 = d * (1 + 2*(x[i].scales[ib32/2] & 0xf)); + const float db2 = d * (1 + 2*(x[i].scales[ib32/2] >> 4)); + for (int l = 0; l < 4; ++l) { + const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*l+0] | ((qh[0] << (8-2*l)) & 256))); + const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*l+1] | ((qh[0] << (7-2*l)) & 256))); + for (int j = 0; j < 4; ++j) { + y[j+0] = db1 * grid1[j] * (signs[l] & kmask_iq2xs[j+0] ? -1.f : 1.f); + y[j+4] = db1 * grid2[j] * (signs[l] & kmask_iq2xs[j+4] ? -1.f : 1.f); + } + y += 8; + } + qs += 8; + signs += 4; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*l+0] | ((qh[1] << (8-2*l)) & 256))); + const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*l+1] | ((qh[1] << (7-2*l)) & 256))); + for (int j = 0; j < 4; ++j) { + y[j+0] = db2 * grid1[j] * (signs[l] & kmask_iq2xs[j+0] ? -1.f : 1.f); + y[j+4] = db2 * grid2[j] * (signs[l] & kmask_iq2xs[j+4] ? -1.f : 1.f); + } + y += 8; + } + qh += 2; + qs += 8; + signs += 4; + } + } +} + +// ====================== 1.5625 bpw (de)-quantization + +void dequantize_row_iq1_s(const block_iq1_s * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const uint8_t * qs = x[i].qs; + const uint16_t * qh = x[i].qh; + + for (int ib = 0; ib < QK_K/32; ++ib) { + const float dl = d * (2*((qh[ib] >> 12) & 7) + 1); + const float delta = qh[ib] & 0x8000 ? -IQ1S_DELTA : IQ1S_DELTA; + for (int l = 0; l < 4; ++l) { + const int8_t * grid = (const int8_t *)(iq1s_grid + (qs[l] | (((qh[ib] >> 3*l) & 7) << 8))); + for (int j = 0; j < 8; ++j) { + y[j] = dl * (grid[j] + delta); + } + y += 8; + } + qs += 4; + } + } +} + +void dequantize_row_iq1_m(const block_iq1_m * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + float delta[4]; + uint16_t idx[4]; + +#if QK_K != 64 + iq1m_scale_t scale; +#endif + + for (int i = 0; i < nb; i++) { + + const uint16_t * sc = (const uint16_t *)x[i].scales; +#if QK_K == 64 + const float d = GGML_FP16_TO_FP32(x[i].d); +#else + scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000); + const float d = GGML_FP16_TO_FP32(scale.f16); +#endif + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + + for (int ib = 0; ib < QK_K/32; ++ib) { +#if QK_K == 64 + const float dl1 = d * (2*((sc[ib/2] >> (8*(ib%2)+0)) & 0xf) + 1); + const float dl2 = d * (2*((sc[ib/2] >> (8*(ib%2)+4)) & 0xf) + 1); +#else + const float dl1 = d * (2*((sc[ib/2] >> (6*(ib%2)+0)) & 0x7) + 1); + const float dl2 = d * (2*((sc[ib/2] >> (6*(ib%2)+3)) & 0x7) + 1); +#endif + idx[0] = qs[0] | ((qh[0] << 8) & 0x700); + idx[1] = qs[1] | ((qh[0] << 4) & 0x700); + idx[2] = qs[2] | ((qh[1] << 8) & 0x700); + idx[3] = qs[3] | ((qh[1] << 4) & 0x700); + delta[0] = qh[0] & 0x08 ? -IQ1S_DELTA : IQ1S_DELTA; + delta[1] = qh[0] & 0x80 ? -IQ1S_DELTA : IQ1S_DELTA; + delta[2] = qh[1] & 0x08 ? -IQ1S_DELTA : IQ1S_DELTA; + delta[3] = qh[1] & 0x80 ? -IQ1S_DELTA : IQ1S_DELTA; + for (int l = 0; l < 2; ++l) { + const int8_t * grid = (const int8_t *)(iq1s_grid + idx[l]); + for (int j = 0; j < 8; ++j) { + y[j] = dl1 * (grid[j] + delta[l]); + } + y += 8; + } + for (int l = 2; l < 4; ++l) { + const int8_t * grid = (const int8_t *)(iq1s_grid + idx[l]); + for (int j = 0; j < 8; ++j) { + y[j] = dl2 * (grid[j] + delta[l]); + } + y += 8; + } + qs += 4; + qh += 2; + } + } +} + +static const int8_t kvalues_iq4nl[16] = {-127, -104, -83, -65, -49, -35, -22, -10, 1, 13, 25, 38, 53, 69, 89, 113}; + +void dequantize_row_iq4_nl(const block_iq4_nl * restrict x, float * restrict y, int64_t k) { + assert(k % QK4_NL == 0); + const int64_t nb = k / QK4_NL; + + for (int i = 0; i < nb; i++) { + + const uint8_t * qs = x[i].qs; + + const float d = GGML_FP16_TO_FP32(x[i].d); + for (int j = 0; j < QK4_NL/2; ++j) { + y[j+ 0] = d * kvalues_iq4nl[qs[j] & 0xf]; + y[j+QK4_NL/2] = d * kvalues_iq4nl[qs[j] >> 4]; + } + y += QK4_NL; + qs += QK4_NL/2; + } +} + +void dequantize_row_iq4_xs(const block_iq4_xs * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); +#if QK_K == 64 + dequantize_row_iq4_nl((const block_iq4_nl *)x, y, k); +#else + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const uint8_t * qs = x[i].qs; + + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int ib = 0; ib < QK_K/32; ++ib) { + const int ls = ((x[i].scales_l[ib/2] >> 4*(ib%2)) & 0xf) | (((x[i].scales_h >> 2*ib) & 3) << 4); + const float dl = d * (ls - 32); + for (int j = 0; j < 16; ++j) { + y[j+ 0] = dl * kvalues_iq4nl[qs[j] & 0xf]; + y[j+16] = dl * kvalues_iq4nl[qs[j] >> 4]; + } + y += 32; + qs += 16; + } + } +#endif +} + +//===================================== Q8_K ============================================== + +void quantize_row_q8_K_reference(const float * restrict x, block_q8_K * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + float max = 0; + float amax = 0; + for (int j = 0; j < QK_K; ++j) { + float ax = fabsf(x[j]); + if (ax > amax) { + amax = ax; max = x[j]; + } + } + if (!amax) { + y[i].d = 0; + memset(y[i].qs, 0, QK_K); + x += QK_K; + continue; + } + //const float iscale = -128.f/max; + // We need this change for IQ2_XXS, else the AVX implementation becomes very awkward + const float iscale = -127.f/max; + for (int j = 0; j < QK_K; ++j) { + int v = nearest_int(iscale*x[j]); + y[i].qs[j] = MIN(127, v); + } + for (int j = 0; j < QK_K/16; ++j) { + int sum = 0; + for (int ii = 0; ii < 16; ++ii) { + sum += y[i].qs[j*16 + ii]; + } + y[i].bsums[j] = sum; + } + y[i].d = 1/iscale; + x += QK_K; + } +} + +void dequantize_row_q8_K(const block_q8_K * restrict x, float * restrict y, int64_t k) { + assert(k % QK_K == 0); + const int64_t nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + for (int j = 0; j < QK_K; ++j) { + *y++ = x[i].d * x[i].qs[j]; + } + } +} + +void quantize_row_q8_K(const float * restrict x, void * restrict y, int64_t k) { + quantize_row_q8_K_reference(x, y, k); +} + +//===================================== Dot ptoducts ================================= + +// +// Helper functions +// +#if __AVX__ || __AVX2__ || __AVX512F__ + +// shuffles to pick the required scales in dot products +static inline __m256i get_scale_shuffle_q3k(int i) { + static const uint8_t k_shuffle[128] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11, + 12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13, 14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15, + }; + return _mm256_loadu_si256((const __m256i*)k_shuffle + i); +} +static inline __m256i get_scale_shuffle_k4(int i) { + static const uint8_t k_shuffle[256] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, + 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11, + 12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13, + 14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15 + }; + return _mm256_loadu_si256((const __m256i*)k_shuffle + i); +} +static inline __m128i get_scale_shuffle(int i) { + static const uint8_t k_shuffle[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11, + 12,12,12,12,12,12,12,12, 13,13,13,13,13,13,13,13, + 14,14,14,14,14,14,14,14, 15,15,15,15,15,15,15,15 + }; + return _mm_loadu_si128((const __m128i*)k_shuffle + i); +} +#endif + +void ggml_vec_dot_q4_0_q8_0(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); +#if defined(__ARM_FEATURE_MATMUL_INT8) + assert((nrc == 2) || (nrc == 1)); +#else + assert(nrc == 1); +#endif + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q4_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_FEATURE_MATMUL_INT8) + if (nrc == 2) { + const block_q4_0 * restrict vx0 = vx; + const block_q4_0 * restrict vx1 = vx + bx; + + const block_q8_0 * restrict vy0 = vy; + const block_q8_0 * restrict vy1 = vy + by; + + float32x4_t sumv0 = vdupq_n_f32(0.0f); + + for (int i = 0; i < nb; i++) { + const block_q4_0 * restrict b_x0 = &vx0[i]; + const block_q4_0 * restrict b_x1 = &vx1[i]; + const block_q8_0 * restrict b_y0 = &vy0[i]; + const block_q8_0 * restrict b_y1 = &vy1[i]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + const int8x16_t s8b = vdupq_n_s8(0x8); + + const uint8x16_t v0_0 = vld1q_u8(b_x0->qs); + const uint8x16_t v0_1 = vld1q_u8(b_x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // sub 8 + const int8x16_t x0_l = vsubq_s8(v0_0l, s8b); + const int8x16_t x0_h = vsubq_s8(v0_0h, s8b); + const int8x16_t x1_l = vsubq_s8(v0_1l, s8b); + const int8x16_t x1_h = vsubq_s8(v0_1h, s8b); + + // load y + const int8x16_t y0_l = vld1q_s8(b_y0->qs); + const int8x16_t y0_h = vld1q_s8(b_y0->qs + 16); + const int8x16_t y1_l = vld1q_s8(b_y1->qs); + const int8x16_t y1_h = vld1q_s8(b_y1->qs + 16); + + float32x4_t scale = {GGML_FP16_TO_FP32(b_x0->d)*GGML_FP16_TO_FP32(b_y0->d), + GGML_FP16_TO_FP32(b_x0->d)*GGML_FP16_TO_FP32(b_y1->d), + GGML_FP16_TO_FP32(b_x1->d)*GGML_FP16_TO_FP32(b_y0->d), + GGML_FP16_TO_FP32(b_x1->d)*GGML_FP16_TO_FP32(b_y1->d)}; + + int8x16_t l0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + int8x16_t l1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + + int8x16_t l2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + int8x16_t l3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + + int8x16_t r0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + int8x16_t r1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + + int8x16_t r2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + int8x16_t r3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + + sumv0 = vmlaq_f32(sumv0,(vcvtq_f32_s32(vmmlaq_s32((vmmlaq_s32((vmmlaq_s32((vmmlaq_s32(vdupq_n_s32(0), l0, r0)), + l1, r1)), l2, r2)), l3, r3))), scale); + } + float32x4_t sumv1 = vextq_f32(sumv0, sumv0, 2); + float32x4_t sumv2 = vzip1q_f32(sumv0, sumv1); + + vst1_f32(s, vget_low_f32(sumv2)); + vst1_f32(s + bs, vget_high_f32(sumv2)); + return; + } +#endif +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q4_0 * restrict x0 = &x[i + 0]; + const block_q4_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i + 0]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + const int8x16_t s8b = vdupq_n_s8(0x8); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // sub 8 + const int8x16_t v0_0ls = vsubq_s8(v0_0l, s8b); + const int8x16_t v0_0hs = vsubq_s8(v0_0h, s8b); + const int8x16_t v0_1ls = vsubq_s8(v0_1l, s8b); + const int8x16_t v0_1hs = vsubq_s8(v0_1h, s8b); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + + // dot product into int32x4_t + const int32x4_t p_0 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), v0_0ls, v1_0l), v0_0hs, v1_0h); + const int32x4_t p_1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), v0_1ls, v1_1l), v0_1hs, v1_1h); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(p_0), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(p_1), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + __m256i qx = bytes_from_nibbles_32(x[i].qs); + + // Now we have a vector with bytes in [ 0 .. 15 ] interval. Offset them into [ -8 .. +7 ] interval. + const __m256i off = _mm256_set1_epi8( 8 ); + qx = _mm256_sub_epi8( qx, off ); + + __m256i qy = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(qx, qy); + + /* Multiply q with scale and accumulate */ + acc = _mm256_fmadd_ps( d, q, acc ); + } + + *s = hsum_float_8(acc); +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + // Compute combined scale for the block + const __m256 d = _mm256_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + const __m128i lowMask = _mm_set1_epi8(0xF); + const __m128i off = _mm_set1_epi8(8); + + const __m128i tmp = _mm_loadu_si128((const __m128i *)x[i].qs); + + __m128i bx_0 = _mm_and_si128(lowMask, tmp); + __m128i by_0 = _mm_loadu_si128((const __m128i *)y[i].qs); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx_0, by_0); + + bx_0 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp, 4)); + by_0 = _mm_loadu_si128((const __m128i *)(y[i].qs + 16)); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx_0, by_0); + + // Convert int32_t to float + __m256 p = _mm256_cvtepi32_ps(MM256_SET_M128I(i32_0, i32_1)); + + // Apply the scale, and accumulate + acc = _mm256_add_ps(_mm256_mul_ps( d, p ), acc); + } + + *s = hsum_float_8(acc); +#elif defined(__SSSE3__) + // set constants + const __m128i lowMask = _mm_set1_epi8(0xF); + const __m128i off = _mm_set1_epi8(8); + + // Initialize accumulator with zeros + __m128 acc_0 = _mm_setzero_ps(); + __m128 acc_1 = _mm_setzero_ps(); + __m128 acc_2 = _mm_setzero_ps(); + __m128 acc_3 = _mm_setzero_ps(); + + // First round without accumulation + { + _mm_prefetch(&x[0] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[0] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 0 and 1 + const __m128 d_0_1 = _mm_set1_ps( GGML_FP16_TO_FP32(x[0].d) * GGML_FP16_TO_FP32(y[0].d) ); + + const __m128i tmp_0_1 = _mm_loadu_si128((const __m128i *)x[0].qs); + + __m128i bx_0 = _mm_and_si128(lowMask, tmp_0_1); + __m128i by_0 = _mm_loadu_si128((const __m128i *)y[0].qs); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx_0, by_0); + + __m128i bx_1 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_0_1, 4)); + __m128i by_1 = _mm_loadu_si128((const __m128i *)(y[0].qs + 16)); + bx_1 = _mm_sub_epi8(bx_1, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx_1, by_1); + + _mm_prefetch(&x[1] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[1] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 2 and 3 + const __m128 d_2_3 = _mm_set1_ps( GGML_FP16_TO_FP32(x[1].d) * GGML_FP16_TO_FP32(y[1].d) ); + + const __m128i tmp_2_3 = _mm_loadu_si128((const __m128i *)x[1].qs); + + __m128i bx_2 = _mm_and_si128(lowMask, tmp_2_3); + __m128i by_2 = _mm_loadu_si128((const __m128i *)y[1].qs); + bx_2 = _mm_sub_epi8(bx_2, off); + const __m128i i32_2 = mul_sum_i8_pairs(bx_2, by_2); + + __m128i bx_3 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_2_3, 4)); + __m128i by_3 = _mm_loadu_si128((const __m128i *)(y[1].qs + 16)); + bx_3 = _mm_sub_epi8(bx_3, off); + const __m128i i32_3 = mul_sum_i8_pairs(bx_3, by_3); + + // Convert int32_t to float + __m128 p0 = _mm_cvtepi32_ps(i32_0); + __m128 p1 = _mm_cvtepi32_ps(i32_1); + __m128 p2 = _mm_cvtepi32_ps(i32_2); + __m128 p3 = _mm_cvtepi32_ps(i32_3); + + // Apply the scale + acc_0 = _mm_mul_ps( d_0_1, p0 ); + acc_1 = _mm_mul_ps( d_0_1, p1 ); + acc_2 = _mm_mul_ps( d_2_3, p2 ); + acc_3 = _mm_mul_ps( d_2_3, p3 ); + } + + assert(nb % 2 == 0); // TODO: handle odd nb + + // Main loop + for (int i = 2; i < nb; i+=2) { + _mm_prefetch(&x[i] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[i] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 0 and 1 + const __m128 d_0_1 = _mm_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + const __m128i tmp_0_1 = _mm_loadu_si128((const __m128i *)x[i].qs); + + __m128i bx_0 = _mm_and_si128(lowMask, tmp_0_1); + __m128i by_0 = _mm_loadu_si128((const __m128i *)y[i].qs); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx_0, by_0); + + __m128i bx_1 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_0_1, 4)); + __m128i by_1 = _mm_loadu_si128((const __m128i *)(y[i].qs + 16)); + bx_1 = _mm_sub_epi8(bx_1, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx_1, by_1); + + _mm_prefetch(&x[i] + 2 * sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[i] + 2 * sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 2 and 3 + const __m128 d_2_3 = _mm_set1_ps( GGML_FP16_TO_FP32(x[i + 1].d) * GGML_FP16_TO_FP32(y[i + 1].d) ); + + const __m128i tmp_2_3 = _mm_loadu_si128((const __m128i *)x[i + 1].qs); + + __m128i bx_2 = _mm_and_si128(lowMask, tmp_2_3); + __m128i by_2 = _mm_loadu_si128((const __m128i *)y[i + 1].qs); + bx_2 = _mm_sub_epi8(bx_2, off); + const __m128i i32_2 = mul_sum_i8_pairs(bx_2, by_2); + + __m128i bx_3 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_2_3, 4)); + __m128i by_3 = _mm_loadu_si128((const __m128i *)(y[i + 1].qs + 16)); + bx_3 = _mm_sub_epi8(bx_3, off); + const __m128i i32_3 = mul_sum_i8_pairs(bx_3, by_3); + + // Convert int32_t to float + __m128 p0 = _mm_cvtepi32_ps(i32_0); + __m128 p1 = _mm_cvtepi32_ps(i32_1); + __m128 p2 = _mm_cvtepi32_ps(i32_2); + __m128 p3 = _mm_cvtepi32_ps(i32_3); + + // Apply the scale + __m128 p0_d = _mm_mul_ps( d_0_1, p0 ); + __m128 p1_d = _mm_mul_ps( d_0_1, p1 ); + __m128 p2_d = _mm_mul_ps( d_2_3, p2 ); + __m128 p3_d = _mm_mul_ps( d_2_3, p3 ); + + // Acummulate + acc_0 = _mm_add_ps(p0_d, acc_0); + acc_1 = _mm_add_ps(p1_d, acc_1); + acc_2 = _mm_add_ps(p2_d, acc_2); + acc_3 = _mm_add_ps(p3_d, acc_3); + } + + *s = hsum_float_4x4(acc_0, acc_1, acc_2, acc_3); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + for (int i = 0; i < nb; i++) { + // load elements + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + // mask and store lower part of x, and then upper part + vuint8mf2_t x_a = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_l = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vint8mf2_t x_ai = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t x_li = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + // subtract offset + vint8mf2_t v0 = __riscv_vsub_vx_i8mf2(x_ai, 8, vl); + vint8mf2_t v1 = __riscv_vsub_vx_i8mf2(x_li, 8, vl); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += sumi*GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const int v0 = (x[i].qs[j] & 0x0F) - 8; + const int v1 = (x[i].qs[j] >> 4) - 8; + + sumi += (v0 * y[i].qs[j]) + (v1 * y[i].qs[j + qk/2]); + } + + sumf += sumi*GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d); + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q4_1_q8_1(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + const int qk = QK8_1; + const int nb = n / qk; + + assert(n % qk == 0); +#if defined(__ARM_FEATURE_MATMUL_INT8) + assert((nrc == 2) || (nrc == 1)); +#else + assert(nrc == 1); +#endif + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q4_1 * restrict x = vx; + const block_q8_1 * restrict y = vy; + +#if defined(__ARM_FEATURE_MATMUL_INT8) + if (nrc == 2) { + const block_q4_1 * restrict vx0 = vx; + const block_q4_1 * restrict vx1 = vx + bx; + const block_q8_1 * restrict vy0 = vy; + const block_q8_1 * restrict vy1 = vy + by; + + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t summs0 = vdupq_n_f32(0.0f); + + for (int i = 0; i < nb; i++) { + const block_q4_1 * restrict b_x0 = &vx0[i]; + const block_q4_1 * restrict b_x1 = &vx1[i]; + const block_q8_1 * restrict b_y0 = &vy0[i]; + const block_q8_1 * restrict b_y1 = &vy1[i]; + + float32x4_t summs_t = {GGML_FP16_TO_FP32(b_x0->m) * GGML_FP16_TO_FP32(b_y0->s), + GGML_FP16_TO_FP32(b_x1->m) * GGML_FP16_TO_FP32(b_y0->s), + GGML_FP16_TO_FP32(b_x0->m) * GGML_FP16_TO_FP32(b_y1->s), + GGML_FP16_TO_FP32(b_x1->m) * GGML_FP16_TO_FP32(b_y1->s)}; + summs0 += summs_t; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + const uint8x16_t v0_0 = vld1q_u8(b_x0->qs); + const uint8x16_t v0_1 = vld1q_u8(b_x1->qs); + + // 4-bit -> 8-bit + const int8x16_t x0_l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t x0_h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t x1_l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t x1_h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // load y + const int8x16_t y0_l = vld1q_s8(b_y0->qs); + const int8x16_t y0_h = vld1q_s8(b_y0->qs + 16); + const int8x16_t y1_l = vld1q_s8(b_y1->qs); + const int8x16_t y1_h = vld1q_s8(b_y1->qs + 16); + + // mmla into int32x4_t + float32x4_t scale = {GGML_FP16_TO_FP32(b_x0->d)*b_y0->d, + GGML_FP16_TO_FP32(b_x0->d)*b_y1->d, + GGML_FP16_TO_FP32(b_x1->d)*b_y0->d, + GGML_FP16_TO_FP32(b_x1->d)*b_y1->d}; + + int8x16_t l0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + int8x16_t l1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + + int8x16_t l2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + int8x16_t l3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + + int8x16_t r0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + int8x16_t r1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + + int8x16_t r2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + int8x16_t r3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + sumv0 = vmlaq_f32(sumv0,(vcvtq_f32_s32(vmmlaq_s32((vmmlaq_s32((vmmlaq_s32((vmmlaq_s32(vdupq_n_s32(0), l0, r0)), + l1, r1)), l2, r2)), l3, r3))), scale); + } + + float32x4_t sumv1 = vextq_f32(sumv0, sumv0, 2); + float32x4_t sumv2 = vzip1q_f32(sumv0, sumv1); + sumv2 = sumv2 + summs0; + + vst1_f32(s, vget_low_f32(sumv2)); + vst1_f32(s + bs, vget_high_f32(sumv2)); + return; + } +#endif + // TODO: add WASM SIMD +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + float summs = 0; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q4_1 * restrict x0 = &x[i + 0]; + const block_q4_1 * restrict x1 = &x[i + 1]; + const block_q8_1 * restrict y0 = &y[i + 0]; + const block_q8_1 * restrict y1 = &y[i + 1]; + + summs += GGML_FP16_TO_FP32(x0->m) * GGML_FP16_TO_FP32(y0->s) + GGML_FP16_TO_FP32(x1->m) * GGML_FP16_TO_FP32(y1->s); + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + + // dot product into int32x4_t + const int32x4_t p_0 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), v0_0l, v1_0l), v0_0h, v1_0h); + const int32x4_t p_1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), v0_1l, v1_1l), v0_1h, v1_1h); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(p_0), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(p_1), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1) + summs; +#elif defined(__AVX2__) || defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + // Main loop + for (int i = 0; i < nb; ++i) { + const float d0 = GGML_FP16_TO_FP32(x[i].d); + const float d1 = GGML_FP16_TO_FP32(y[i].d); + + summs += GGML_FP16_TO_FP32(x[i].m) * GGML_FP16_TO_FP32(y[i].s); + + const __m256 d0v = _mm256_set1_ps( d0 ); + const __m256 d1v = _mm256_set1_ps( d1 ); + + // Compute combined scales + const __m256 d0d1 = _mm256_mul_ps( d0v, d1v ); + + // Load 16 bytes, and unpack 4 bit fields into bytes, making 32 bytes + const __m256i qx = bytes_from_nibbles_32(x[i].qs); + const __m256i qy = _mm256_loadu_si256( (const __m256i *)y[i].qs ); + + const __m256 xy = mul_sum_us8_pairs_float(qx, qy); + + // Accumulate d0*d1*x*y +#if defined(__AVX2__) + acc = _mm256_fmadd_ps( d0d1, xy, acc ); +#else + acc = _mm256_add_ps( _mm256_mul_ps( d0d1, xy ), acc ); +#endif + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + for (int i = 0; i < nb; i++) { + // load elements + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + // mask and store lower part of x, and then upper part + vuint8mf2_t x_a = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_l = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vint8mf2_t v0 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t v1 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d))*sumi + GGML_FP16_TO_FP32(x[i].m)*GGML_FP16_TO_FP32(y[i].s); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const int v0 = (x[i].qs[j] & 0x0F); + const int v1 = (x[i].qs[j] >> 4); + + sumi += (v0 * y[i].qs[j]) + (v1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d))*sumi + GGML_FP16_TO_FP32(x[i].m)*GGML_FP16_TO_FP32(y[i].s); + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q5_0_q8_0(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); + assert(qk == QK5_0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q5_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + uint32_t qh0; + uint32_t qh1; + + uint64_t tmp0[4]; + uint64_t tmp1[4]; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q5_0 * restrict x0 = &x[i]; + const block_q5_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + // extract the 5th bit via lookup table ((!b) << 4) + memcpy(&qh0, x0->qh, sizeof(qh0)); + memcpy(&qh1, x1->qh, sizeof(qh1)); + + tmp0[0] = table_b2b_1[(qh0 >> 0) & 0xFF]; + tmp0[1] = table_b2b_1[(qh0 >> 8) & 0xFF]; + tmp0[2] = table_b2b_1[(qh0 >> 16) & 0xFF]; + tmp0[3] = table_b2b_1[(qh0 >> 24) ]; + + tmp1[0] = table_b2b_1[(qh1 >> 0) & 0xFF]; + tmp1[1] = table_b2b_1[(qh1 >> 8) & 0xFF]; + tmp1[2] = table_b2b_1[(qh1 >> 16) & 0xFF]; + tmp1[3] = table_b2b_1[(qh1 >> 24) ]; + + const int8x16_t qhl0 = vld1q_s8((const int8_t *)(tmp0 + 0)); + const int8x16_t qhh0 = vld1q_s8((const int8_t *)(tmp0 + 2)); + const int8x16_t qhl1 = vld1q_s8((const int8_t *)(tmp1 + 0)); + const int8x16_t qhh1 = vld1q_s8((const int8_t *)(tmp1 + 2)); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // add high bit and sub 16 (equivalent to sub 0x10 when bit is zero) + const int8x16_t v0_0lf = vsubq_s8(v0_0l, qhl0); + const int8x16_t v0_0hf = vsubq_s8(v0_0h, qhh0); + const int8x16_t v0_1lf = vsubq_s8(v0_1l, qhl1); + const int8x16_t v0_1hf = vsubq_s8(v0_1h, qhh1); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), v0_0lf, v1_0l), + ggml_vdotq_s32(vdupq_n_s32(0), v0_0hf, v1_0h))), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), v0_1lf, v1_1l), + ggml_vdotq_s32(vdupq_n_s32(0), v0_1hf, v1_1h))), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__wasm_simd128__) + v128_t sumv = wasm_f32x4_splat(0.0f); + + uint32_t qh; + uint64_t tmp[4]; + + // TODO: check if unrolling this is better + for (int i = 0; i < nb; ++i) { + const block_q5_0 * restrict x0 = &x[i]; + const block_q8_0 * restrict y0 = &y[i]; + + const v128_t m4b = wasm_i8x16_splat(0x0F); + + // extract the 5th bit + memcpy(&qh, x0->qh, sizeof(qh)); + + tmp[0] = table_b2b_1[(qh >> 0) & 0xFF]; + tmp[1] = table_b2b_1[(qh >> 8) & 0xFF]; + tmp[2] = table_b2b_1[(qh >> 16) & 0xFF]; + tmp[3] = table_b2b_1[(qh >> 24) ]; + + const v128_t qhl = wasm_v128_load(tmp + 0); + const v128_t qhh = wasm_v128_load(tmp + 2); + + const v128_t v0 = wasm_v128_load(x0->qs); + + // 4-bit -> 8-bit + const v128_t v0l = wasm_v128_and (v0, m4b); + const v128_t v0h = wasm_u8x16_shr(v0, 4); + + // add high bit and sub 16 (equivalent to sub 0x10 when bit is zero) + const v128_t v0lf = wasm_i8x16_sub(v0l, qhl); + const v128_t v0hf = wasm_i8x16_sub(v0h, qhh); + + // load y + const v128_t v1l = wasm_v128_load(y0->qs); + const v128_t v1h = wasm_v128_load(y0->qs + 16); + + // int8x16 -> int16x8 + const v128_t v0lfl = wasm_i16x8_extend_low_i8x16 (v0lf); + const v128_t v0lfh = wasm_i16x8_extend_high_i8x16(v0lf); + const v128_t v0hfl = wasm_i16x8_extend_low_i8x16 (v0hf); + const v128_t v0hfh = wasm_i16x8_extend_high_i8x16(v0hf); + + const v128_t v1ll = wasm_i16x8_extend_low_i8x16 (v1l); + const v128_t v1lh = wasm_i16x8_extend_high_i8x16(v1l); + const v128_t v1hl = wasm_i16x8_extend_low_i8x16 (v1h); + const v128_t v1hh = wasm_i16x8_extend_high_i8x16(v1h); + + // dot product + sumv = wasm_f32x4_add(sumv, wasm_f32x4_mul(wasm_f32x4_convert_i32x4( + wasm_i32x4_add( + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0lfl, v1ll), + wasm_i32x4_dot_i16x8(v0lfh, v1lh)), + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0hfl, v1hl), + wasm_i32x4_dot_i16x8(v0hfh, v1hh)))), + wasm_f32x4_splat(GGML_FP16_TO_FP32(x0->d) * GGML_FP16_TO_FP32(y0->d)))); + } + + *s = wasm_f32x4_extract_lane(sumv, 0) + wasm_f32x4_extract_lane(sumv, 1) + + wasm_f32x4_extract_lane(sumv, 2) + wasm_f32x4_extract_lane(sumv, 3); +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; i++) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + + __m256i qx = bytes_from_nibbles_32(x[i].qs); + __m256i bxhi = bytes_from_bits_32(x[i].qh); + bxhi = _mm256_andnot_si256(bxhi, _mm256_set1_epi8((char)0xF0)); + qx = _mm256_or_si256(qx, bxhi); + + __m256i qy = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(qx, qy); + + /* Multiply q with scale and accumulate */ + acc = _mm256_fmadd_ps(d, q, acc); + } + + *s = hsum_float_8(acc); +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + __m128i mask = _mm_set1_epi8((char)0xF0); + + // Main loop + for (int i = 0; i < nb; i++) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + + __m256i bx_0 = bytes_from_nibbles_32(x[i].qs); + const __m256i bxhi = bytes_from_bits_32(x[i].qh); + __m128i bxhil = _mm256_castsi256_si128(bxhi); + __m128i bxhih = _mm256_extractf128_si256(bxhi, 1); + bxhil = _mm_andnot_si128(bxhil, mask); + bxhih = _mm_andnot_si128(bxhih, mask); + __m128i bxl = _mm256_castsi256_si128(bx_0); + __m128i bxh = _mm256_extractf128_si256(bx_0, 1); + bxl = _mm_or_si128(bxl, bxhil); + bxh = _mm_or_si128(bxh, bxhih); + bx_0 = MM256_SET_M128I(bxh, bxl); + + const __m256i by_0 = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(bx_0, by_0); + + /* Multiply q with scale and accumulate */ + acc = _mm256_add_ps(_mm256_mul_ps(d, q), acc); + } + + *s = hsum_float_8(acc); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + uint32_t qh; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + // These temporary registers are for masking and shift operations + vuint32m2_t vt_1 = __riscv_vid_v_u32m2(vl); + vuint32m2_t vt_2 = __riscv_vsll_vv_u32m2(__riscv_vmv_v_x_u32m2(1, vl), vt_1, vl); + + vuint32m2_t vt_3 = __riscv_vsll_vx_u32m2(vt_2, 16, vl); + vuint32m2_t vt_4 = __riscv_vadd_vx_u32m2(vt_1, 12, vl); + + for (int i = 0; i < nb; i++) { + memcpy(&qh, x[i].qh, sizeof(uint32_t)); + + // ((qh & (1u << (j + 0 ))) >> (j + 0 )) << 4; + vuint32m2_t xha_0 = __riscv_vand_vx_u32m2(vt_2, qh, vl); + vuint32m2_t xhr_0 = __riscv_vsrl_vv_u32m2(xha_0, vt_1, vl); + vuint32m2_t xhl_0 = __riscv_vsll_vx_u32m2(xhr_0, 4, vl); + + // ((qh & (1u << (j + 16))) >> (j + 12)); + vuint32m2_t xha_1 = __riscv_vand_vx_u32m2(vt_3, qh, vl); + vuint32m2_t xhl_1 = __riscv_vsrl_vv_u32m2(xha_1, vt_4, vl); + + // narrowing + vuint16m1_t xhc_0 = __riscv_vncvt_x_x_w_u16m1(xhl_0, vl); + vuint8mf2_t xh_0 = __riscv_vncvt_x_x_w_u8mf2(xhc_0, vl); + + vuint16m1_t xhc_1 = __riscv_vncvt_x_x_w_u16m1(xhl_1, vl); + vuint8mf2_t xh_1 = __riscv_vncvt_x_x_w_u8mf2(xhc_1, vl); + + // load + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + vuint8mf2_t x_at = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_lt = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vuint8mf2_t x_a = __riscv_vor_vv_u8mf2(x_at, xh_0, vl); + vuint8mf2_t x_l = __riscv_vor_vv_u8mf2(x_lt, xh_1, vl); + + vint8mf2_t x_ai = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t x_li = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint8mf2_t v0 = __riscv_vsub_vx_i8mf2(x_ai, 16, vl); + vint8mf2_t v1 = __riscv_vsub_vx_i8mf2(x_li, 16, vl); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)) * sumi; + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh & (1u << (j + 0 ))) >> (j + 0 )) << 4; + const uint8_t xh_1 = ((qh & (1u << (j + 16))) >> (j + 12)); + + const int32_t x0 = ((x[i].qs[j] & 0x0F) | xh_0) - 16; + const int32_t x1 = ((x[i].qs[j] >> 4) | xh_1) - 16; + + sumi += (x0 * y[i].qs[j]) + (x1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)) * sumi; + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q5_1_q8_1(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + const int qk = QK8_1; + const int nb = n / qk; + + assert(n % qk == 0); + assert(qk == QK5_1); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q5_1 * restrict x = vx; + const block_q8_1 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + float summs0 = 0.0f; + float summs1 = 0.0f; + + uint32_t qh0; + uint32_t qh1; + + uint64_t tmp0[4]; + uint64_t tmp1[4]; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q5_1 * restrict x0 = &x[i]; + const block_q5_1 * restrict x1 = &x[i + 1]; + const block_q8_1 * restrict y0 = &y[i]; + const block_q8_1 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + summs0 += GGML_FP16_TO_FP32(x0->m) * GGML_FP16_TO_FP32(y0->s); + summs1 += GGML_FP16_TO_FP32(x1->m) * GGML_FP16_TO_FP32(y1->s); + + // extract the 5th bit via lookup table ((b) << 4) + memcpy(&qh0, x0->qh, sizeof(qh0)); + memcpy(&qh1, x1->qh, sizeof(qh1)); + + tmp0[0] = table_b2b_0[(qh0 >> 0) & 0xFF]; + tmp0[1] = table_b2b_0[(qh0 >> 8) & 0xFF]; + tmp0[2] = table_b2b_0[(qh0 >> 16) & 0xFF]; + tmp0[3] = table_b2b_0[(qh0 >> 24) ]; + + tmp1[0] = table_b2b_0[(qh1 >> 0) & 0xFF]; + tmp1[1] = table_b2b_0[(qh1 >> 8) & 0xFF]; + tmp1[2] = table_b2b_0[(qh1 >> 16) & 0xFF]; + tmp1[3] = table_b2b_0[(qh1 >> 24) ]; + + const int8x16_t qhl0 = vld1q_s8((const int8_t *)(tmp0 + 0)); + const int8x16_t qhh0 = vld1q_s8((const int8_t *)(tmp0 + 2)); + const int8x16_t qhl1 = vld1q_s8((const int8_t *)(tmp1 + 0)); + const int8x16_t qhh1 = vld1q_s8((const int8_t *)(tmp1 + 2)); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // add high bit + const int8x16_t v0_0lf = vorrq_s8(v0_0l, qhl0); + const int8x16_t v0_0hf = vorrq_s8(v0_0h, qhh0); + const int8x16_t v0_1lf = vorrq_s8(v0_1l, qhl1); + const int8x16_t v0_1hf = vorrq_s8(v0_1h, qhh1); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), v0_0lf, v1_0l), + ggml_vdotq_s32(vdupq_n_s32(0), v0_0hf, v1_0h))), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), v0_1lf, v1_1l), + ggml_vdotq_s32(vdupq_n_s32(0), v0_1hf, v1_1h))), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1) + summs0 + summs1; +#elif defined(__wasm_simd128__) + v128_t sumv = wasm_f32x4_splat(0.0f); + + float summs = 0.0f; + + uint32_t qh; + uint64_t tmp[4]; + + // TODO: check if unrolling this is better + for (int i = 0; i < nb; ++i) { + const block_q5_1 * restrict x0 = &x[i]; + const block_q8_1 * restrict y0 = &y[i]; + + summs += GGML_FP16_TO_FP32(x0->m) * GGML_FP16_TO_FP32(y0->s); + + const v128_t m4b = wasm_i8x16_splat(0x0F); + + // extract the 5th bit + memcpy(&qh, x0->qh, sizeof(qh)); + + tmp[0] = table_b2b_0[(qh >> 0) & 0xFF]; + tmp[1] = table_b2b_0[(qh >> 8) & 0xFF]; + tmp[2] = table_b2b_0[(qh >> 16) & 0xFF]; + tmp[3] = table_b2b_0[(qh >> 24) ]; + + const v128_t qhl = wasm_v128_load(tmp + 0); + const v128_t qhh = wasm_v128_load(tmp + 2); + + const v128_t v0 = wasm_v128_load(x0->qs); + + // 4-bit -> 8-bit + const v128_t v0l = wasm_v128_and (v0, m4b); + const v128_t v0h = wasm_u8x16_shr(v0, 4); + + // add high bit + const v128_t v0lf = wasm_v128_or(v0l, qhl); + const v128_t v0hf = wasm_v128_or(v0h, qhh); + + // load y + const v128_t v1l = wasm_v128_load(y0->qs); + const v128_t v1h = wasm_v128_load(y0->qs + 16); + + // int8x16 -> int16x8 + const v128_t v0lfl = wasm_i16x8_extend_low_i8x16 (v0lf); + const v128_t v0lfh = wasm_i16x8_extend_high_i8x16(v0lf); + const v128_t v0hfl = wasm_i16x8_extend_low_i8x16 (v0hf); + const v128_t v0hfh = wasm_i16x8_extend_high_i8x16(v0hf); + + const v128_t v1ll = wasm_i16x8_extend_low_i8x16 (v1l); + const v128_t v1lh = wasm_i16x8_extend_high_i8x16(v1l); + const v128_t v1hl = wasm_i16x8_extend_low_i8x16 (v1h); + const v128_t v1hh = wasm_i16x8_extend_high_i8x16(v1h); + + // dot product + sumv = wasm_f32x4_add(sumv, + wasm_f32x4_mul(wasm_f32x4_convert_i32x4(wasm_i32x4_add( + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0lfl, v1ll), + wasm_i32x4_dot_i16x8(v0lfh, v1lh)), + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0hfl, v1hl), + wasm_i32x4_dot_i16x8(v0hfh, v1hh)))), + wasm_f32x4_splat(GGML_FP16_TO_FP32(x0->d) * GGML_FP16_TO_FP32(y0->d)))); + } + + *s = wasm_f32x4_extract_lane(sumv, 0) + wasm_f32x4_extract_lane(sumv, 1) + + wasm_f32x4_extract_lane(sumv, 2) + wasm_f32x4_extract_lane(sumv, 3) + summs; +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.0f; + + // Main loop + for (int i = 0; i < nb; i++) { + const __m256 dx = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d)); + + summs += GGML_FP16_TO_FP32(x[i].m) * GGML_FP16_TO_FP32(y[i].s); + + __m256i qx = bytes_from_nibbles_32(x[i].qs); + __m256i bxhi = bytes_from_bits_32(x[i].qh); + bxhi = _mm256_and_si256(bxhi, _mm256_set1_epi8(0x10)); + qx = _mm256_or_si256(qx, bxhi); + + const __m256 dy = _mm256_set1_ps(GGML_FP16_TO_FP32(y[i].d)); + const __m256i qy = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_us8_pairs_float(qx, qy); + + acc = _mm256_fmadd_ps(q, _mm256_mul_ps(dx, dy), acc); + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + __m128i mask = _mm_set1_epi8(0x10); + + float summs = 0.0f; + + // Main loop + for (int i = 0; i < nb; i++) { + const __m256 dx = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d)); + + summs += GGML_FP16_TO_FP32(x[i].m) * GGML_FP16_TO_FP32(y[i].s); + + __m256i bx_0 = bytes_from_nibbles_32(x[i].qs); + const __m256i bxhi = bytes_from_bits_32(x[i].qh); + __m128i bxhil = _mm256_castsi256_si128(bxhi); + __m128i bxhih = _mm256_extractf128_si256(bxhi, 1); + bxhil = _mm_and_si128(bxhil, mask); + bxhih = _mm_and_si128(bxhih, mask); + __m128i bxl = _mm256_castsi256_si128(bx_0); + __m128i bxh = _mm256_extractf128_si256(bx_0, 1); + bxl = _mm_or_si128(bxl, bxhil); + bxh = _mm_or_si128(bxh, bxhih); + bx_0 = MM256_SET_M128I(bxh, bxl); + + const __m256 dy = _mm256_set1_ps(GGML_FP16_TO_FP32(y[i].d)); + const __m256i by_0 = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_us8_pairs_float(bx_0, by_0); + + acc = _mm256_add_ps(_mm256_mul_ps(q, _mm256_mul_ps(dx, dy)), acc); + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + uint32_t qh; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + // temporary registers for shift operations + vuint32m2_t vt_1 = __riscv_vid_v_u32m2(vl); + vuint32m2_t vt_2 = __riscv_vadd_vx_u32m2(vt_1, 12, vl); + + for (int i = 0; i < nb; i++) { + memcpy(&qh, x[i].qh, sizeof(uint32_t)); + + // load qh + vuint32m2_t vqh = __riscv_vmv_v_x_u32m2(qh, vl); + + // ((qh >> (j + 0)) << 4) & 0x10; + vuint32m2_t xhr_0 = __riscv_vsrl_vv_u32m2(vqh, vt_1, vl); + vuint32m2_t xhl_0 = __riscv_vsll_vx_u32m2(xhr_0, 4, vl); + vuint32m2_t xha_0 = __riscv_vand_vx_u32m2(xhl_0, 0x10, vl); + + // ((qh >> (j + 12)) ) & 0x10; + vuint32m2_t xhr_1 = __riscv_vsrl_vv_u32m2(vqh, vt_2, vl); + vuint32m2_t xha_1 = __riscv_vand_vx_u32m2(xhr_1, 0x10, vl); + + // narrowing + vuint16m1_t xhc_0 = __riscv_vncvt_x_x_w_u16m1(xha_0, vl); + vuint8mf2_t xh_0 = __riscv_vncvt_x_x_w_u8mf2(xhc_0, vl); + + vuint16m1_t xhc_1 = __riscv_vncvt_x_x_w_u16m1(xha_1, vl); + vuint8mf2_t xh_1 = __riscv_vncvt_x_x_w_u8mf2(xhc_1, vl); + + // load + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + vuint8mf2_t x_at = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_lt = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vuint8mf2_t x_a = __riscv_vor_vv_u8mf2(x_at, xh_0, vl); + vuint8mf2_t x_l = __riscv_vor_vv_u8mf2(x_lt, xh_1, vl); + + vint8mf2_t v0 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t v1 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d))*sumi + GGML_FP16_TO_FP32(x[i].m)*GGML_FP16_TO_FP32(y[i].s); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int32_t x0 = (x[i].qs[j] & 0xF) | xh_0; + const int32_t x1 = (x[i].qs[j] >> 4) | xh_1; + + sumi += (x0 * y[i].qs[j]) + (x1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d))*sumi + GGML_FP16_TO_FP32(x[i].m)*GGML_FP16_TO_FP32(y[i].s); + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q8_0_q8_0(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); +#if defined(__ARM_FEATURE_MATMUL_INT8) + assert((nrc == 2) || (nrc == 1)); +#else + assert(nrc == 1); +#endif + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q8_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_FEATURE_MATMUL_INT8) + if (nrc == 2) { + const block_q8_0 * restrict vx0 = vx; + const block_q8_0 * restrict vx1 = vx + bx; + const block_q8_0 * restrict vy0 = vy; + const block_q8_0 * restrict vy1 = vy + by; + + float32x4_t sumv0 = vdupq_n_f32(0.0f); + + for (int i = 0; i < nb; i++) { + const block_q8_0 * restrict b_x0 = &vx0[i]; + const block_q8_0 * restrict b_y0 = &vy0[i]; + + const block_q8_0 * restrict b_x1 = &vx1[i]; + const block_q8_0 * restrict b_y1 = &vy1[i]; + + const int8x16_t x0_l = vld1q_s8(b_x0->qs); + const int8x16_t x0_h = vld1q_s8(b_x0->qs + 16); + const int8x16_t x1_l = vld1q_s8(b_x1->qs); + const int8x16_t x1_h = vld1q_s8(b_x1->qs + 16); + + // load y + const int8x16_t y0_l = vld1q_s8(b_y0->qs); + const int8x16_t y0_h = vld1q_s8(b_y0->qs + 16); + const int8x16_t y1_l = vld1q_s8(b_y1->qs); + const int8x16_t y1_h = vld1q_s8(b_y1->qs + 16); + + float32x4_t scale = {GGML_FP16_TO_FP32(b_x0->d)*GGML_FP16_TO_FP32(b_y0->d), + GGML_FP16_TO_FP32(b_x0->d)*GGML_FP16_TO_FP32(b_y1->d), + GGML_FP16_TO_FP32(b_x1->d)*GGML_FP16_TO_FP32(b_y0->d), + GGML_FP16_TO_FP32(b_x1->d)*GGML_FP16_TO_FP32(b_y1->d)}; + + int8x16_t l0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + int8x16_t l1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_l), vreinterpretq_s64_s8(x1_l))); + + int8x16_t l2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + int8x16_t l3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(x0_h), vreinterpretq_s64_s8(x1_h))); + + int8x16_t r0 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + int8x16_t r1 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_l), vreinterpretq_s64_s8(y1_l))); + + int8x16_t r2 = vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + int8x16_t r3 = vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(y0_h), vreinterpretq_s64_s8(y1_h))); + + sumv0 = vmlaq_f32(sumv0,(vcvtq_f32_s32(vmmlaq_s32((vmmlaq_s32((vmmlaq_s32((vmmlaq_s32(vdupq_n_s32(0), l0, r0)), + l1, r1)), l2, r2)), l3, r3))), scale); + } + float32x4_t sumv1 = vextq_f32(sumv0, sumv0, 2); + float32x4_t sumv2 = vzip1q_f32(sumv0, sumv1); + + vst1_f32(s, vget_low_f32(sumv2)); + vst1_f32(s + bs, vget_high_f32(sumv2)); + return; + } +#endif +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q8_0 * restrict x0 = &x[i + 0]; + const block_q8_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i + 0]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const int8x16_t x0_0 = vld1q_s8(x0->qs); + const int8x16_t x0_1 = vld1q_s8(x0->qs + 16); + const int8x16_t x1_0 = vld1q_s8(x1->qs); + const int8x16_t x1_1 = vld1q_s8(x1->qs + 16); + + // load y + const int8x16_t y0_0 = vld1q_s8(y0->qs); + const int8x16_t y0_1 = vld1q_s8(y0->qs + 16); + const int8x16_t y1_0 = vld1q_s8(y1->qs); + const int8x16_t y1_1 = vld1q_s8(y1->qs + 16); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), x0_0, y0_0), + ggml_vdotq_s32(vdupq_n_s32(0), x0_1, y0_1))), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + ggml_vdotq_s32(vdupq_n_s32(0), x1_0, y1_0), + ggml_vdotq_s32(vdupq_n_s32(0), x1_1, y1_1))), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__AVX2__) || defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + // Compute combined scale for the block + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + __m256i qx = _mm256_loadu_si256((const __m256i *)x[i].qs); + __m256i qy = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(qx, qy); + + // Multiply q with scale and accumulate +#if defined(__AVX2__) + acc = _mm256_fmadd_ps( d, q, acc ); +#else + acc = _mm256_add_ps( _mm256_mul_ps( d, q ), acc ); +#endif + } + + *s = hsum_float_8(acc); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + size_t vl = __riscv_vsetvl_e8m1(qk); + + for (int i = 0; i < nb; i++) { + // load elements + vint8m1_t bx_0 = __riscv_vle8_v_i8m1(x[i].qs, vl); + vint8m1_t by_0 = __riscv_vle8_v_i8m1(y[i].qs, vl); + + vint16m2_t vw_mul = __riscv_vwmul_vv_i16m2(bx_0, by_0, vl); + + vint32m1_t v_zero = __riscv_vmv_v_x_i32m1(0, vl); + vint32m1_t v_sum = __riscv_vwredsum_vs_i16m2_i32m1(vw_mul, v_zero, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(v_sum); + + sumf += sumi*(GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk; j++) { + sumi += x[i].qs[j]*y[i].qs[j]; + } + + sumf += sumi*(GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)); + } + + *s = sumf; +#endif +} + +#if QK_K == 256 +void ggml_vec_dot_q2_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q2_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + const uint8x16_t m3 = vdupq_n_u8(0x3); + const uint8x16_t m4 = vdupq_n_u8(0xF); + + const int32x4_t vzero = vdupq_n_s32(0); + + ggml_int8x16x2_t q2bytes; + uint8_t aux[16]; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint8_t * restrict sc = x[i].scales; + + const uint8x16_t mins_and_scales = vld1q_u8(sc); + const uint8x16_t scales = vandq_u8(mins_and_scales, m4); + vst1q_u8(aux, scales); + + const uint8x16_t mins = vshrq_n_u8(mins_and_scales, 4); + const ggml_int16x8x2_t q8sums = ggml_vld1q_s16_x2(y[i].bsums); + const ggml_int16x8x2_t mins16 = {{vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(mins))), vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(mins)))}}; + const int32x4_t s0 = vaddq_s32(vmull_s16(vget_low_s16 (mins16.val[0]), vget_low_s16 (q8sums.val[0])), + vmull_s16(vget_high_s16(mins16.val[0]), vget_high_s16(q8sums.val[0]))); + const int32x4_t s1 = vaddq_s32(vmull_s16(vget_low_s16 (mins16.val[1]), vget_low_s16 (q8sums.val[1])), + vmull_s16(vget_high_s16(mins16.val[1]), vget_high_s16(q8sums.val[1]))); + sum += dmin * vaddvq_s32(vaddq_s32(s0, s1)); + + int isum = 0; + int is = 0; + +// We use this macro instead of a function call because for some reason +// the code runs 2-3% slower, even if the function is declared inline +#define MULTIPLY_ACCUM_WITH_SCALE(index)\ + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[0], q8bytes.val[0])) * aux[is+(index)];\ + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[1], q8bytes.val[1])) * aux[is+1+(index)]; + +#define SHIFT_MULTIPLY_ACCUM_WITH_SCALE(shift, index)\ + q8bytes = ggml_vld1q_s8_x2(q8); q8 += 32;\ + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits.val[0], (shift)), m3));\ + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits.val[1], (shift)), m3));\ + MULTIPLY_ACCUM_WITH_SCALE((index)); + + for (int j = 0; j < QK_K/128; ++j) { + const ggml_uint8x16x2_t q2bits = ggml_vld1q_u8_x2(q2); q2 += 32; + + ggml_int8x16x2_t q8bytes = ggml_vld1q_s8_x2(q8); q8 += 32; + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(q2bits.val[0], m3)); + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(q2bits.val[1], m3)); + + MULTIPLY_ACCUM_WITH_SCALE(0); + + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(2, 2); + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(4, 4); + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(6, 6); + + is += 8; + } + + sum += d * isum; + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m128i m4 = _mm_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m128i mins_and_scales = _mm_loadu_si128((const __m128i*)x[i].scales); + const __m128i scales8 = _mm_and_si128(mins_and_scales, m4); + const __m128i mins8 = _mm_and_si128(_mm_srli_epi16(mins_and_scales, 4), m4); + const __m256i mins = _mm256_cvtepi8_epi16(mins8); + const __m256i prod = _mm256_madd_epi16(mins, _mm256_loadu_si256((const __m256i*)y[i].bsums)); + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&dmin), _mm256_cvtepi32_ps(prod), acc); + + const __m256i all_scales = _mm256_cvtepi8_epi16(scales8); + const __m128i l_scales = _mm256_extracti128_si256(all_scales, 0); + const __m128i h_scales = _mm256_extracti128_si256(all_scales, 1); + const __m256i scales[2] = {MM256_SET_M128I(l_scales, l_scales), MM256_SET_M128I(h_scales, h_scales)}; + + __m256i sumi = _mm256_setzero_si256(); + + for (int j = 0; j < QK_K/128; ++j) { + + const __m256i q2bits = _mm256_loadu_si256((const __m256i*)q2); q2 += 32; + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + const __m256i q2_0 = _mm256_and_si256(q2bits, m3); + const __m256i q2_1 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 2), m3); + const __m256i q2_2 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 4), m3); + const __m256i q2_3 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 6), m3); + + __m256i p0 = _mm256_maddubs_epi16(q2_0, q8_0); + __m256i p1 = _mm256_maddubs_epi16(q2_1, q8_1); + __m256i p2 = _mm256_maddubs_epi16(q2_2, q8_2); + __m256i p3 = _mm256_maddubs_epi16(q2_3, q8_3); + + p0 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(0)), p0); + p1 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(1)), p1); + p2 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(2)), p2); + p3 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(3)), p3); + + p0 = _mm256_add_epi32(p0, p1); + p2 = _mm256_add_epi32(p2, p3); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p0, p2)); + } + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(0x3); + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(0x2); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // load mins and scales from block_q2_K.scales[QK_K/16] + const __m128i mins_and_scales = _mm_loadu_si128((const __m128i*)x[i].scales); + const __m128i scales16 = _mm_and_si128(mins_and_scales, m4); + const __m128i mins16 = _mm_and_si128(_mm_srli_epi16(mins_and_scales, 4), m4); + const __m128i mins_0 = _mm_cvtepi8_epi16(mins16); + const __m128i mins_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(mins16, mins16)); + + // summs = y[i].bsums * (x[i].scales >> 4) in 16bits*8*2 to 32bits*4*2 + const __m128i summs_0 = _mm_madd_epi16(mins_0, _mm_loadu_si128((const __m128i*)&y[i].bsums[0])); + const __m128i summs_1 = _mm_madd_epi16(mins_1, _mm_loadu_si128((const __m128i*)&y[i].bsums[8])); + + // sumf += -dmin * summs in 32bits*8 + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&dmin), _mm256_cvtepi32_ps(MM256_SET_M128I(summs_1, summs_0))), acc); + + const __m128i scales_0 = _mm_cvtepi8_epi16(scales16); + const __m128i scales_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(scales16, scales16)); + const __m128i scales[2] = { scales_0, scales_1 }; + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + for (int j = 0; j < QK_K/128; ++j) { + + // load Q8 quants int8*16*8 from block_q8_K.qs[QK_K] + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + // load 2bits*16*8 from block_q2_K.qs[QK_K/4] + __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); q2 += 16; + const __m128i q2_0 = _mm_and_si128(q2bits, m3); + const __m128i q2_2 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_4 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_6 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + q2bits = _mm_loadu_si128((const __m128i*)q2); q2 += 16; + const __m128i q2_1 = _mm_and_si128(q2bits, m3); + const __m128i q2_3 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_5 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_7 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + + // isuml = q8[l] * ((q2[l] >> shift) & 3) in 8bits*16*8 to 16bits*8*8 + __m128i p0 = _mm_maddubs_epi16(q2_0, q8_0); + __m128i p1 = _mm_maddubs_epi16(q2_1, q8_1); + __m128i p2 = _mm_maddubs_epi16(q2_2, q8_2); + __m128i p3 = _mm_maddubs_epi16(q2_3, q8_3); + __m128i p4 = _mm_maddubs_epi16(q2_4, q8_4); + __m128i p5 = _mm_maddubs_epi16(q2_5, q8_5); + __m128i p6 = _mm_maddubs_epi16(q2_6, q8_6); + __m128i p7 = _mm_maddubs_epi16(q2_7, q8_7); + + // isum += (x[i].scales[is++] & 0xF) * isuml in 16bits*8*8 to 32bits*4*8 + __m128i shuffle = _mm_set1_epi16(0x0100); + p0 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p0); + shuffle = _mm_add_epi16(shuffle, m2); + p1 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p1); + shuffle = _mm_add_epi16(shuffle, m2); + p2 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p2); + shuffle = _mm_add_epi16(shuffle, m2); + p3 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p3); + shuffle = _mm_add_epi16(shuffle, m2); + p4 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p4); + shuffle = _mm_add_epi16(shuffle, m2); + p5 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p5); + shuffle = _mm_add_epi16(shuffle, m2); + p6 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p6); + shuffle = _mm_add_epi16(shuffle, m2); + p7 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p7); + + p0 = _mm_add_epi32(p0, p1); + p2 = _mm_add_epi32(p2, p3); + p4 = _mm_add_epi32(p4, p5); + p6 = _mm_add_epi32(p6, p7); + + // isum in 32bits*4*2 + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p0, p2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p4, p6)); + } + + // sumf += dall * isum - dmin * summs in 32bits + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&dall), _mm256_cvtepi32_ps(sumi)), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + uint8_t temp_01[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + size_t vl = 16; + + vuint8m1_t scales = __riscv_vle8_v_u8m1(sc, vl); + vuint8m1_t aux = __riscv_vand_vx_u8m1(scales, 0x0F, vl); + + vint16m1_t q8sums = __riscv_vle16_v_i16m1(y[i].bsums, vl); + + vuint8mf2_t scales_2 = __riscv_vle8_v_u8mf2(sc, vl); + vuint8mf2_t mins8 = __riscv_vsrl_vx_u8mf2(scales_2, 0x4, vl); + vint16m1_t mins = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2_u16m1(mins8, vl)); + vint32m2_t prod = __riscv_vwmul_vv_i32m2(q8sums, mins, vl); + vint32m1_t vsums = __riscv_vredsum_vs_i32m2_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + + sumf += dmin * __riscv_vmv_x_s_i32m1_i32(vsums); + + vl = 32; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t v_b = __riscv_vle8_v_u8m1(temp_01, vl); + + uint8_t is=0; + int isum=0; + + for (int j = 0; j < QK_K/128; ++j) { + // load Q2 + vuint8m1_t q2_x = __riscv_vle8_v_u8m1(q2, vl); + + vuint8m1_t q2_0 = __riscv_vand_vx_u8m1(q2_x, 0x03, vl); + vuint8m1_t q2_1 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x2, vl), 0x03 , vl); + vuint8m1_t q2_2 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x4, vl), 0x03 , vl); + vuint8m1_t q2_3 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x6, vl), 0x03 , vl); + + // duplicate scale elements for product + vuint8m1_t sc0 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 0+is, vl), vl); + vuint8m1_t sc1 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 2+is, vl), vl); + vuint8m1_t sc2 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 4+is, vl), vl); + vuint8m1_t sc3 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 6+is, vl), vl); + + vint16m2_t p0 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_0, sc0, vl)); + vint16m2_t p1 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_1, sc1, vl)); + vint16m2_t p2 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_2, sc2, vl)); + vint16m2_t p3 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_3, sc3, vl)); + + // load Q8 + vint8m1_t q8_0 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q8_1 = __riscv_vle8_v_i8m1(q8+32, vl); + vint8m1_t q8_2 = __riscv_vle8_v_i8m1(q8+64, vl); + vint8m1_t q8_3 = __riscv_vle8_v_i8m1(q8+96, vl); + + vint32m4_t s0 = __riscv_vwmul_vv_i32m4(p0, __riscv_vwcvt_x_x_v_i16m2(q8_0, vl), vl); + vint32m4_t s1 = __riscv_vwmul_vv_i32m4(p1, __riscv_vwcvt_x_x_v_i16m2(q8_1, vl), vl); + vint32m4_t s2 = __riscv_vwmul_vv_i32m4(p2, __riscv_vwcvt_x_x_v_i16m2(q8_2, vl), vl); + vint32m4_t s3 = __riscv_vwmul_vv_i32m4(p3, __riscv_vwcvt_x_x_v_i16m2(q8_3, vl), vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m4_i32m1(__riscv_vadd_vv_i32m4(s0, s1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m4_i32m1(__riscv_vadd_vv_i32m4(s2, s3, vl), isum0, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(isum1); + + q2+=32; q8+=128; is=8; + + } + + sumf += dall * isum; + + } + + *s = sumf; + +#else + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + int summs = 0; + for (int j = 0; j < 16; ++j) { + summs += y[i].bsums[j] * (sc[j] >> 4); + } + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + int isum = 0; + int is = 0; + int d; + for (int k = 0; k < QK_K/128; ++k) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + d = sc[is++] & 0xF; + int isuml = 0; + for (int l = 0; l < 16; ++l) isuml += q8[l] * ((q2[l] >> shift) & 3); + isum += d * isuml; + d = sc[is++] & 0xF; + isuml = 0; + for (int l = 16; l < 32; ++l) isuml += q8[l] * ((q2[l] >> shift) & 3); + isum += d * isuml; + shift += 2; + q8 += 32; + } + q2 += 32; + } + sumf += dall * isum - dmin * summs; + } + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q2_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q2_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + const uint8x16_t m3 = vdupq_n_u8(0x3); + + const int32x4_t vzero = vdupq_n_s32(0); + + ggml_int8x16x4_t q2bytes; + + uint32_t aux32[2]; + const uint8_t * scales = (const uint8_t *)aux32; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + + aux32[0] = sc[0] & 0x0f0f0f0f; + aux32[1] = (sc[0] >> 4) & 0x0f0f0f0f; + + sum += dmin * (scales[4] * y[i].bsums[0] + scales[5] * y[i].bsums[1] + scales[6] * y[i].bsums[2] + scales[7] * y[i].bsums[3]); + + int isum1 = 0, isum2 = 0; + + const uint8x16_t q2bits = vld1q_u8(q2); + + const ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(q8); + + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(q2bits, m3)); + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 2), m3)); + q2bytes.val[2] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 4), m3)); + q2bytes.val[3] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 6), m3)); + + isum1 += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[0], q8bytes.val[0])) * scales[0]; + isum2 += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[1], q8bytes.val[1])) * scales[1]; + isum1 += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[2], q8bytes.val[2])) * scales[2]; + isum2 += vaddvq_s32(ggml_vdotq_s32(vzero, q2bytes.val[3], q8bytes.val[3])) * scales[3]; + + sum += d * (isum1 + isum2); + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t ud, um; + const uint8_t * restrict db = (const uint8_t *)&ud; + const uint8_t * restrict mb = (const uint8_t *)&um; + + float summs = 0; + + // TODO: optimize this + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + ud = (sc[0] >> 0) & 0x0f0f0f0f; + um = (sc[0] >> 4) & 0x0f0f0f0f; + + int32_t smin = mb[0] * y[i].bsums[0] + mb[1] * y[i].bsums[1] + mb[2] * y[i].bsums[2] + mb[3] * y[i].bsums[3]; + summs += dmin * smin; + + const __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); + const __m256i q2_0 = _mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q2bits, 2), q2bits), m3); + const __m256i q2_1 = _mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q2bits, 6), _mm_srli_epi16(q2bits, 4)), m3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p0 = _mm256_maddubs_epi16(q2_0, q8_0); + const __m256i p1 = _mm256_maddubs_epi16(q2_1, q8_1); + + const __m256i p_0 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p0, 0)); + const __m256i p_1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p0, 1)); + const __m256i p_2 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p1, 0)); + const __m256i p_3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p1, 1)); + + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[0]), _mm256_cvtepi32_ps(p_0), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[1]), _mm256_cvtepi32_ps(p_1), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[2]), _mm256_cvtepi32_ps(p_2), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[3]), _mm256_cvtepi32_ps(p_3), acc); + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t ud, um; + const uint8_t * restrict db = (const uint8_t *)&ud; + const uint8_t * restrict mb = (const uint8_t *)&um; + + float summs = 0; + + // TODO: optimize this + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + ud = (sc[0] >> 0) & 0x0f0f0f0f; + um = (sc[0] >> 4) & 0x0f0f0f0f; + + int32_t smin = mb[0] * y[i].bsums[0] + mb[1] * y[i].bsums[1] + mb[2] * y[i].bsums[2] + mb[3] * y[i].bsums[3]; + summs += dmin * smin; + + const __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); + const __m128i q2_0 = _mm_and_si128(q2bits, m3); + const __m128i q2_1 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_2 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_3 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p0 = _mm_maddubs_epi16(q2_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i p1 = _mm_maddubs_epi16(q2_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i p2 = _mm_maddubs_epi16(q2_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i p3 = _mm_maddubs_epi16(q2_3, _mm256_extractf128_si256(q8_1, 1)); + + const __m256i p_0 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p0, p0)), _mm_cvtepi16_epi32(p0)); + const __m256i p_1 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p1, p1)), _mm_cvtepi16_epi32(p1)); + const __m256i p_2 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p2, p2)), _mm_cvtepi16_epi32(p2)); + const __m256i p_3 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p3, p3)), _mm_cvtepi16_epi32(p3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[0]), _mm256_cvtepi32_ps(p_0)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[1]), _mm256_cvtepi32_ps(p_1)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[2]), _mm256_cvtepi32_ps(p_2)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[3]), _mm256_cvtepi32_ps(p_3)), acc); + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __riscv_v_intrinsic + + uint32_t aux32[2]; + const uint8_t * scales = (const uint8_t *)aux32; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + + aux32[0] = sc[0] & 0x0f0f0f0f; + aux32[1] = (sc[0] >> 4) & 0x0f0f0f0f; + + sumf += dmin * (scales[4] * y[i].bsums[0] + scales[5] * y[i].bsums[1] + scales[6] * y[i].bsums[2] + scales[7] * y[i].bsums[3]); + + int isum1 = 0; + int isum2 = 0; + + size_t vl = 16; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + // load Q2 + vuint8mf2_t q2_x = __riscv_vle8_v_u8mf2(q2, vl); + + vint8mf2_t q2_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q2_x, 0x03, vl)); + vint8mf2_t q2_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x2, vl), 0x03 , vl)); + vint8mf2_t q2_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x4, vl), 0x03 , vl)); + vint8mf2_t q2_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x6, vl), 0x03 , vl)); + + // load Q8, and take product with Q2 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q2_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q2_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q2_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q2_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint16m1_t vs_0 = __riscv_vredsum_vs_i16m1_i16m1(p0, vzero, vl); + vint16m1_t vs_1 = __riscv_vredsum_vs_i16m1_i16m1(p1, vzero, vl); + vint16m1_t vs_2 = __riscv_vredsum_vs_i16m1_i16m1(p2, vzero, vl); + vint16m1_t vs_3 = __riscv_vredsum_vs_i16m1_i16m1(p3, vzero, vl); + + isum1 += __riscv_vmv_x_s_i16m1_i16(vs_0) * scales[0]; + isum2 += __riscv_vmv_x_s_i16m1_i16(vs_1) * scales[1]; + isum1 += __riscv_vmv_x_s_i16m1_i16(vs_2) * scales[2]; + isum2 += __riscv_vmv_x_s_i16m1_i16(vs_3) * scales[3]; + + sumf += d * (isum1 + isum2); + + } + + *s = sumf; + +#else + + float sumf = 0; + + int isum[QK_K/16]; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + int summs = 0; + for (int j = 0; j < QK_K/16; ++j) { + summs += y[i].bsums[j] * (sc[j] >> 4); + } + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + memset(isum, 0, (QK_K/16)*sizeof(int)); + for (int l = 0; l < 16; ++l) { + isum[0] += q8[l+ 0] * ((q2[l] >> 0) & 3); + isum[1] += q8[l+16] * ((q2[l] >> 2) & 3); + isum[2] += q8[l+32] * ((q2[l] >> 4) & 3); + isum[3] += q8[l+48] * ((q2[l] >> 6) & 3); + } + for (int l = 0; l < QK_K/16; ++l) { + isum[l] *= (sc[l] & 0xF); + } + sumf += dall * (isum[0] + isum[1] + isum[2] + isum[3]) - dmin * summs; + } + *s = sumf; +#endif +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q3_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const uint32_t kmask1 = 0x03030303; + const uint32_t kmask2 = 0x0f0f0f0f; + + const block_q3_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + uint32_t aux[3]; + uint32_t utmp[4]; + + const uint8x16_t m3b = vdupq_n_u8(0x3); + const int32x4_t vzero = vdupq_n_s32(0); + + const uint8x16_t m0 = vdupq_n_u8(1); + const uint8x16_t m1 = vshlq_n_u8(m0, 1); + const uint8x16_t m2 = vshlq_n_u8(m0, 2); + const uint8x16_t m3 = vshlq_n_u8(m0, 3); + const int8_t m32 = 32; + + ggml_int8x16x4_t q3bytes; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict qh = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + + ggml_uint8x16x2_t qhbits = ggml_vld1q_u8_x2(qh); + + ggml_uint8x16x4_t q3h; + + int32_t isum = 0; + + // Set up scales + memcpy(aux, x[i].scales, 12); + utmp[3] = ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4); + utmp[2] = ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4); + utmp[1] = (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4); + utmp[0] = (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4); + + int8_t * scale = (int8_t *)utmp; + for (int j = 0; j < 16; ++j) scale[j] -= m32; + + for (int j = 0; j < QK_K/128; ++j) { + + const ggml_uint8x16x2_t q3bits = ggml_vld1q_u8_x2(q3); q3 += 32; + const ggml_int8x16x4_t q8bytes_1 = ggml_vld1q_s8_x4(q8); q8 += 64; + const ggml_int8x16x4_t q8bytes_2 = ggml_vld1q_s8_x4(q8); q8 += 64; + + q3h.val[0] = vshlq_n_u8(vbicq_u8(m0, qhbits.val[0]), 2); + q3h.val[1] = vshlq_n_u8(vbicq_u8(m0, qhbits.val[1]), 2); + q3h.val[2] = vshlq_n_u8(vbicq_u8(m1, qhbits.val[0]), 1); + q3h.val[3] = vshlq_n_u8(vbicq_u8(m1, qhbits.val[1]), 1); + + q3bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q3bits.val[0], m3b)), vreinterpretq_s8_u8(q3h.val[0])); + q3bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q3bits.val[1], m3b)), vreinterpretq_s8_u8(q3h.val[1])); + q3bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 2), m3b)), vreinterpretq_s8_u8(q3h.val[2])); + q3bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 2), m3b)), vreinterpretq_s8_u8(q3h.val[3])); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[0], q8bytes_1.val[0])) * scale[0]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[1], q8bytes_1.val[1])) * scale[1]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[2], q8bytes_1.val[2])) * scale[2]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[3], q8bytes_1.val[3])) * scale[3]; + + scale += 4; + + q3h.val[0] = vbicq_u8(m2, qhbits.val[0]); + q3h.val[1] = vbicq_u8(m2, qhbits.val[1]); + q3h.val[2] = vshrq_n_u8(vbicq_u8(m3, qhbits.val[0]), 1); + q3h.val[3] = vshrq_n_u8(vbicq_u8(m3, qhbits.val[1]), 1); + + q3bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 4), m3b)), vreinterpretq_s8_u8(q3h.val[0])); + q3bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 4), m3b)), vreinterpretq_s8_u8(q3h.val[1])); + q3bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 6), m3b)), vreinterpretq_s8_u8(q3h.val[2])); + q3bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 6), m3b)), vreinterpretq_s8_u8(q3h.val[3])); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[0], q8bytes_2.val[0])) * scale[0]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[1], q8bytes_2.val[1])) * scale[1]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[2], q8bytes_2.val[2])) * scale[2]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[3], q8bytes_2.val[3])) * scale[3]; + + scale += 4; + + if (j == 0) { + qhbits.val[0] = vshrq_n_u8(qhbits.val[0], 4); + qhbits.val[1] = vshrq_n_u8(qhbits.val[1], 4); + } + + } + sum += d * isum; + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m256i mone = _mm256_set1_epi8(1); + const __m128i m32 = _mm_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t aux[3]; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // Set up scales + memcpy(aux, x[i].scales, 12); + __m128i scales128 = _mm_set_epi32( + ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4), + ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4), + (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4), + (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4)); + scales128 = _mm_sub_epi8(scales128, m32); + const __m256i all_scales = _mm256_cvtepi8_epi16(scales128); + const __m128i l_scales = _mm256_extracti128_si256(all_scales, 0); + const __m128i h_scales = _mm256_extracti128_si256(all_scales, 1); + const __m256i scales[2] = {MM256_SET_M128I(l_scales, l_scales), MM256_SET_M128I(h_scales, h_scales)}; + + // high bit + const __m256i hbits = _mm256_loadu_si256((const __m256i*)x[i].hmask); + + // integer accumulator + __m256i sumi = _mm256_setzero_si256(); + + int bit = 0; + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + // load low 2 bits + const __m256i q3bits = _mm256_loadu_si256((const __m256i*)q3); q3 += 32; + + // prepare low and high bits + const __m256i q3l_0 = _mm256_and_si256(q3bits, m3); + const __m256i q3h_0 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_1 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 2), m3); + const __m256i q3h_1 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_2 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 4), m3); + const __m256i q3h_2 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_3 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 6), m3); + const __m256i q3h_3 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + __m256i q8s_0 = _mm256_maddubs_epi16(q3h_0, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(q3h_1, q8_1); + __m256i q8s_2 = _mm256_maddubs_epi16(q3h_2, q8_2); + __m256i q8s_3 = _mm256_maddubs_epi16(q3h_3, q8_3); + + __m256i p16_0 = _mm256_maddubs_epi16(q3l_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q3l_1, q8_1); + __m256i p16_2 = _mm256_maddubs_epi16(q3l_2, q8_2); + __m256i p16_3 = _mm256_maddubs_epi16(q3l_3, q8_3); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + p16_2 = _mm256_sub_epi16(p16_2, q8s_2); + p16_3 = _mm256_sub_epi16(p16_3, q8s_3); + + // multiply with scales + p16_0 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 0)), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 1)), p16_1); + p16_2 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 2)), p16_2); + p16_3 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 3)), p16_3); + + // accumulate + p16_0 = _mm256_add_epi32(p16_0, p16_1); + p16_2 = _mm256_add_epi32(p16_2, p16_3); + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_2)); + + } + + // multiply with block scale and accumulate + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + const __m128i mone = _mm_set1_epi8(1); + const __m128i m32 = _mm_set1_epi8(32); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + const uint32_t *aux; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // Set up scales + aux = (const uint32_t *)x[i].scales; + __m128i scales128 = _mm_set_epi32( + ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4), + ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4), + (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4), + (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4)); + scales128 = _mm_sub_epi8(scales128, m32); + const __m128i scales_0 = _mm_cvtepi8_epi16(scales128); + const __m128i scales_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(scales128, scales128)); + const __m128i scales[2] = { scales_0, scales_1 }; + + // high bit *128*2 from block_q3_K.hmask[QK_K/8] + const __m128i hbits_0 = _mm_loadu_si128((const __m128i*)&x[i].hmask[0]); + const __m128i hbits_1 = _mm_loadu_si128((const __m128i*)&x[i].hmask[16]); + + // integer accumulator + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + for (int j = 0; j < QK_K/128; ++j) { + // load low 2 bits *64*2 from block_q3_K.qs[QK_K/4] + const __m128i q3bits_0 = _mm_loadu_si128((const __m128i*)q3); q3 += 16; + const __m128i q3bits_1 = _mm_loadu_si128((const __m128i*)q3); q3 += 16; + + // prepare low and high bits + const int bit = j << 2; + + const __m128i q3l_0 = _mm_and_si128(q3bits_0, m3); + const __m128i q3l_1 = _mm_and_si128(q3bits_1, m3); + const __m128i q3h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit)), bit), 2); + const __m128i q3h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit)), bit), 2); + + const __m128i q3l_2 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 2), m3); + const __m128i q3l_3 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 2), m3); + const __m128i q3h_2 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+1)), bit+1), 2); + const __m128i q3h_3 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+1)), bit+1), 2); + + const __m128i q3l_4 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 4), m3); + const __m128i q3l_5 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 4), m3); + const __m128i q3h_4 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+2)), bit+2), 2); + const __m128i q3h_5 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+2)), bit+2), 2); + + const __m128i q3l_6 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 6), m3); + const __m128i q3l_7 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 6), m3); + const __m128i q3h_6 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+3)), bit+3), 2); + const __m128i q3h_7 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+3)), bit+3), 2); + + // load Q8 quants from block_q8_K.qs[QK_K] + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + __m128i q8s_0 = _mm_maddubs_epi16(q3h_0, q8_0); + __m128i q8s_1 = _mm_maddubs_epi16(q3h_1, q8_1); + __m128i q8s_2 = _mm_maddubs_epi16(q3h_2, q8_2); + __m128i q8s_3 = _mm_maddubs_epi16(q3h_3, q8_3); + __m128i q8s_4 = _mm_maddubs_epi16(q3h_4, q8_4); + __m128i q8s_5 = _mm_maddubs_epi16(q3h_5, q8_5); + __m128i q8s_6 = _mm_maddubs_epi16(q3h_6, q8_6); + __m128i q8s_7 = _mm_maddubs_epi16(q3h_7, q8_7); + + __m128i p16_0 = _mm_maddubs_epi16(q3l_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q3l_1, q8_1); + __m128i p16_2 = _mm_maddubs_epi16(q3l_2, q8_2); + __m128i p16_3 = _mm_maddubs_epi16(q3l_3, q8_3); + __m128i p16_4 = _mm_maddubs_epi16(q3l_4, q8_4); + __m128i p16_5 = _mm_maddubs_epi16(q3l_5, q8_5); + __m128i p16_6 = _mm_maddubs_epi16(q3l_6, q8_6); + __m128i p16_7 = _mm_maddubs_epi16(q3l_7, q8_7); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + p16_4 = _mm_sub_epi16(p16_4, q8s_4); + p16_5 = _mm_sub_epi16(p16_5, q8s_5); + p16_6 = _mm_sub_epi16(p16_6, q8s_6); + p16_7 = _mm_sub_epi16(p16_7, q8s_7); + + // multiply with scales + __m128i shuffle = _mm_set1_epi16(0x0100); + p16_0 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_0); + shuffle = _mm_add_epi16(shuffle, m2); + p16_1 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_1); + shuffle = _mm_add_epi16(shuffle, m2); + p16_2 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_2); + shuffle = _mm_add_epi16(shuffle, m2); + p16_3 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_3); + shuffle = _mm_add_epi16(shuffle, m2); + p16_4 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_4); + shuffle = _mm_add_epi16(shuffle, m2); + p16_5 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_5); + shuffle = _mm_add_epi16(shuffle, m2); + p16_6 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_6); + shuffle = _mm_add_epi16(shuffle, m2); + p16_7 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_7); + + // accumulate + p16_0 = _mm_add_epi32(p16_0, p16_1); + p16_2 = _mm_add_epi32(p16_2, p16_3); + p16_4 = _mm_add_epi32(p16_4, p16_5); + p16_6 = _mm_add_epi32(p16_6, p16_7); + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_4, p16_6)); + + } + + // multiply with block scale and accumulate + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi)), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + uint32_t aux[3]; + uint32_t utmp[4]; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict qh = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + + memcpy(aux, x[i].scales, 12); + utmp[3] = ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4); + utmp[2] = ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4); + utmp[1] = (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4); + utmp[0] = (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4); + + int8_t * scale = (int8_t *)utmp; + for (int j = 0; j < 16; ++j) scale[j] -= 32; + + + size_t vl = 32; + uint8_t m = 1; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t vqh = __riscv_vle8_v_u8m1(qh, vl); + + int sum_t = 0; + + for (int j = 0; j < QK_K; j += 128) { + + vl = 32; + + // load Q3 + vuint8m1_t q3_x = __riscv_vle8_v_u8m1(q3, vl); + + vint8m1_t q3_0 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q3_x, 0x03, vl)); + vint8m1_t q3_1 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x2, vl), 0x03 , vl)); + vint8m1_t q3_2 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x4, vl), 0x03 , vl)); + vint8m1_t q3_3 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x6, vl), 0x03 , vl)); + + // compute mask for subtraction + vuint8m1_t qh_m0 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_0 = __riscv_vmseq_vx_u8m1_b8(qh_m0, 0, vl); + vint8m1_t q3_m0 = __riscv_vsub_vx_i8m1_m(vmask_0, q3_0, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m1 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_1 = __riscv_vmseq_vx_u8m1_b8(qh_m1, 0, vl); + vint8m1_t q3_m1 = __riscv_vsub_vx_i8m1_m(vmask_1, q3_1, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m2 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_2 = __riscv_vmseq_vx_u8m1_b8(qh_m2, 0, vl); + vint8m1_t q3_m2 = __riscv_vsub_vx_i8m1_m(vmask_2, q3_2, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m3 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_3 = __riscv_vmseq_vx_u8m1_b8(qh_m3, 0, vl); + vint8m1_t q3_m3 = __riscv_vsub_vx_i8m1_m(vmask_3, q3_3, 0x4, vl); + m <<= 1; + + // load Q8 and take product with Q3 + vint16m2_t a0 = __riscv_vwmul_vv_i16m2(q3_m0, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m2_t a1 = __riscv_vwmul_vv_i16m2(q3_m1, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m2_t a2 = __riscv_vwmul_vv_i16m2(q3_m2, __riscv_vle8_v_i8m1(q8+64, vl), vl); + vint16m2_t a3 = __riscv_vwmul_vv_i16m2(q3_m3, __riscv_vle8_v_i8m1(q8+96, vl), vl); + + vl = 16; + + // retrieve lane to multiply with scale + vint32m2_t aux0_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a0, 0), (scale[0]), vl); + vint32m2_t aux0_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a0, 1), (scale[1]), vl); + vint32m2_t aux1_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a1, 0), (scale[2]), vl); + vint32m2_t aux1_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a1, 1), (scale[3]), vl); + vint32m2_t aux2_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a2, 0), (scale[4]), vl); + vint32m2_t aux2_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a2, 1), (scale[5]), vl); + vint32m2_t aux3_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a3, 0), (scale[6]), vl); + vint32m2_t aux3_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a3, 1), (scale[7]), vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux0_0, aux0_1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux1_0, aux1_1, vl), isum0, vl); + vint32m1_t isum2 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux2_0, aux2_1, vl), isum1, vl); + vint32m1_t isum3 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux3_0, aux3_1, vl), isum2, vl); + + sum_t += __riscv_vmv_x_s_i32m1_i32(isum3); + + q3 += 32; q8 += 128; scale += 8; + + } + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + + sumf += d*sum_t; + + } + + *s = sumf; + +#else + // scalar version + // This function is written like this so the compiler can manage to vectorize most of it + // Using -Ofast, GCC and clang manage to produce code that is within a factor of 2 or so from the + // manually vectorized version above. Every other version I tried would run at least 4 times slower. + // The ideal situation would be if we could just write the code once, and the compiler would + // automatically produce the best possible set of machine instructions, instead of us having to manually + // write vectorized versions for AVX, ARM_NEON, etc. + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + uint32_t auxs[4]; + const int8_t * scales = (const int8_t*)auxs; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + uint8_t m = 1; + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) a[l] = q3[l] & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 2) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 4) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 6) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + q3 += 32; + } + a = aux8; + + memcpy(auxs, x[i].scales, 12); + uint32_t tmp = auxs[2]; + auxs[2] = ((auxs[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4); + auxs[3] = ((auxs[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4); + auxs[0] = (auxs[0] & kmask2) | (((tmp >> 0) & kmask1) << 4); + auxs[1] = (auxs[1] & kmask2) | (((tmp >> 2) & kmask1) << 4); + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += (scales[j] - 32) * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += (scales[j] - 32) * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; + +#endif + +} + +#else + +void ggml_vec_dot_q3_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q3_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + const int32x4_t vzero = vdupq_n_s32(0); + + const uint8x16_t m3b = vdupq_n_u8(0x3); + const uint8x16_t mh = vdupq_n_u8(4); + + ggml_int8x16x4_t q3bytes; + + uint16_t aux16[2]; + int8_t * scales = (int8_t *)aux16; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + ggml_uint8x16x4_t q3h; + + const uint8x8_t hbits = vld1_u8(x[i].hmask); + const uint8x16_t q3bits = vld1q_u8(x[i].qs); + const ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(y[i].qs); + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + for (int j = 0; j < 4; ++j) scales[j] -= 8; + + int32_t isum = -4*(scales[0] * y[i].bsums[0] + scales[2] * y[i].bsums[1] + scales[1] * y[i].bsums[2] + scales[3] * y[i].bsums[3]); + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8x16_t htmp = vcombine_u8(hbits, vshr_n_u8(hbits, 1)); + q3h.val[0] = vandq_u8(mh, vshlq_n_u8(htmp, 2)); + q3h.val[1] = vandq_u8(mh, htmp); + q3h.val[2] = vandq_u8(mh, vshrq_n_u8(htmp, 2)); + q3h.val[3] = vandq_u8(mh, vshrq_n_u8(htmp, 4)); + + q3bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q3bits, m3b), q3h.val[0])); + q3bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(vshrq_n_u8(q3bits, 2), m3b), q3h.val[1])); + q3bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(vshrq_n_u8(q3bits, 4), m3b), q3h.val[2])); + q3bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q3bits, 6), q3h.val[3])); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[0], q8bytes.val[0])) * scales[0]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[1], q8bytes.val[1])) * scales[2]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[2], q8bytes.val[2])) * scales[1]; + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q3bytes.val[3], q8bytes.val[3])) * scales[3]; + + sum += d * isum; + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m256i m1 = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + uint64_t aux64; + + uint16_t aux16[2]; + const int8_t * aux8 = (const int8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + const __m256i scale_0 = MM256_SET_M128I(_mm_set1_epi16(aux8[2] - 8), _mm_set1_epi16(aux8[0] - 8)); + const __m256i scale_1 = MM256_SET_M128I(_mm_set1_epi16(aux8[3] - 8), _mm_set1_epi16(aux8[1] - 8)); + + memcpy(&aux64, x[i].hmask, 8); + + const __m128i haux = _mm_set_epi64x(aux64 >> 1, aux64 >> 0); + __m256i q3h_0 = MM256_SET_M128I(_mm_srli_epi16(haux, 2), haux); + __m256i q3h_1 = _mm256_srli_epi16(q3h_0, 4); + q3h_0 = _mm256_slli_epi16(_mm256_andnot_si256(q3h_0, m1), 2); + q3h_1 = _mm256_slli_epi16(_mm256_andnot_si256(q3h_1, m1), 2); + + // load low 2 bits + const __m128i q3bits = _mm_loadu_si128((const __m128i*)q3); + + // prepare low and high bits + const __m256i q3aux = MM256_SET_M128I(_mm_srli_epi16(q3bits, 2), q3bits); + const __m256i q3l_0 = _mm256_and_si256(q3aux, m3); + const __m256i q3l_1 = _mm256_and_si256(_mm256_srli_epi16(q3aux, 4), m3); + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + const __m256i q8s_0 = _mm256_maddubs_epi16(q3h_0, q8_0); + const __m256i q8s_1 = _mm256_maddubs_epi16(q3h_1, q8_1); + + __m256i p16_0 = _mm256_maddubs_epi16(q3l_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q3l_1, q8_1); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + + // multiply with scales + p16_0 = _mm256_madd_epi16(scale_0, p16_0); + p16_1 = _mm256_madd_epi16(scale_1, p16_1); + + p16_0 = _mm256_add_epi32(p16_0, p16_1); + + // multiply with block scale and accumulate + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(p16_0), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + const __m128i m1 = _mm_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + uint64_t aux64; + + uint16_t aux16[2]; + const int8_t * aux8 = (const int8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + const __m128i scale_0 = _mm_set1_epi16(aux8[0] - 8); + const __m128i scale_1 = _mm_set1_epi16(aux8[2] - 8); + const __m128i scale_2 = _mm_set1_epi16(aux8[1] - 8); + const __m128i scale_3 = _mm_set1_epi16(aux8[3] - 8); + + memcpy(&aux64, x[i].hmask, 8); + + __m128i q3h_0 = _mm_set_epi64x(aux64 >> 1, aux64 >> 0); + __m128i q3h_1 = _mm_srli_epi16(q3h_0, 2); + __m128i q3h_2 = _mm_srli_epi16(q3h_0, 4); + __m128i q3h_3 = _mm_srli_epi16(q3h_0, 6); + q3h_0 = _mm_slli_epi16(_mm_andnot_si128(q3h_0, m1), 2); + q3h_1 = _mm_slli_epi16(_mm_andnot_si128(q3h_1, m1), 2); + q3h_2 = _mm_slli_epi16(_mm_andnot_si128(q3h_2, m1), 2); + q3h_3 = _mm_slli_epi16(_mm_andnot_si128(q3h_3, m1), 2); + + // load low 2 bits + const __m128i q3bits = _mm_loadu_si128((const __m128i*)q3); + + // prepare low and high bits + const __m128i q3l_0 = _mm_and_si128(q3bits, m3); + const __m128i q3l_1 = _mm_and_si128(_mm_srli_epi16(q3bits, 2), m3); + const __m128i q3l_2 = _mm_and_si128(_mm_srli_epi16(q3bits, 4), m3); + const __m128i q3l_3 = _mm_and_si128(_mm_srli_epi16(q3bits, 6), m3); + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + const __m128i q8s_0 = _mm_maddubs_epi16(q3h_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i q8s_1 = _mm_maddubs_epi16(q3h_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i q8s_2 = _mm_maddubs_epi16(q3h_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i q8s_3 = _mm_maddubs_epi16(q3h_3, _mm256_extractf128_si256(q8_1, 1)); + + __m128i p16_0 = _mm_maddubs_epi16(q3l_0, _mm256_extractf128_si256(q8_0, 0)); + __m128i p16_1 = _mm_maddubs_epi16(q3l_1, _mm256_extractf128_si256(q8_0, 1)); + __m128i p16_2 = _mm_maddubs_epi16(q3l_2, _mm256_extractf128_si256(q8_1, 0)); + __m128i p16_3 = _mm_maddubs_epi16(q3l_3, _mm256_extractf128_si256(q8_1, 1)); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + + // multiply with scales + p16_0 = _mm_madd_epi16(scale_0, p16_0); + p16_1 = _mm_madd_epi16(scale_1, p16_1); + p16_2 = _mm_madd_epi16(scale_2, p16_2); + p16_3 = _mm_madd_epi16(scale_3, p16_3); + + p16_0 = _mm_add_epi32(p16_0, p16_2); + p16_1 = _mm_add_epi32(p16_1, p16_3); + __m256i p16 = MM256_SET_M128I(p16_1, p16_0); + + // multiply with block scale and accumulate + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(p16)), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + uint16_t aux16[2]; + int8_t * scales = (int8_t *)aux16; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + for (int j = 0; j < 4; ++j) scales[j] -= 8; + + int32_t isum = -4*(scales[0] * y[i].bsums[0] + scales[2] * y[i].bsums[1] + scales[1] * y[i].bsums[2] + scales[3] * y[i].bsums[3]); + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load qh + vuint8mf4_t qh_x1 = __riscv_vle8_v_u8mf4(x[i].hmask, 8); + vuint8mf2_t qh_x2 = __riscv_vlmul_ext_v_u8mf4_u8mf2(__riscv_vsrl_vx_u8mf4(qh_x1, 1, 8)); + + size_t vl = 16; + + // extend and combine both qh_x1 and qh_x2 + vuint8mf2_t qh_x = __riscv_vslideup_vx_u8mf2(__riscv_vlmul_ext_v_u8mf4_u8mf2(qh_x1), qh_x2, vl/2, vl); + + vuint8mf2_t qh_0 = __riscv_vand_vx_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x2, vl), 0x4, vl); + vuint8mf2_t qh_1 = __riscv_vand_vx_u8mf2(qh_x, 0x4, vl); + vuint8mf2_t qh_2 = __riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl), 0x4, vl); + vuint8mf2_t qh_3 = __riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x4, vl), 0x4, vl); + + // load Q3 + vuint8mf2_t q3_x = __riscv_vle8_v_u8mf2(q3, vl); + + vuint8mf2_t q3h_0 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q3_x, 0x3, vl), qh_0, vl); + vuint8mf2_t q3h_1 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 2, vl), 0x3, vl), qh_1, vl); + vuint8mf2_t q3h_2 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 4, vl), 0x3, vl), qh_2, vl); + vuint8mf2_t q3h_3 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 0x6, vl), qh_3, vl); + + vint8mf2_t q3_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_0); + vint8mf2_t q3_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_1); + vint8mf2_t q3_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_2); + vint8mf2_t q3_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_3); + + // load Q8 and take product with Q3 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q3_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q3_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q3_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q3_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(vs_0) * scales[0]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_1) * scales[2]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_2) * scales[1]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_3) * scales[3]; + + sumf += d * isum; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + int32_t scales[4]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + int8_t * restrict a = aux8; + for (int l = 0; l < 8; ++l) { + a[l+ 0] = (int8_t)((q3[l+0] >> 0) & 3) - (hm[l] & 0x01 ? 0 : 4); + a[l+ 8] = (int8_t)((q3[l+8] >> 0) & 3) - (hm[l] & 0x02 ? 0 : 4); + a[l+16] = (int8_t)((q3[l+0] >> 2) & 3) - (hm[l] & 0x04 ? 0 : 4); + a[l+24] = (int8_t)((q3[l+8] >> 2) & 3) - (hm[l] & 0x08 ? 0 : 4); + a[l+32] = (int8_t)((q3[l+0] >> 4) & 3) - (hm[l] & 0x10 ? 0 : 4); + a[l+40] = (int8_t)((q3[l+8] >> 4) & 3) - (hm[l] & 0x20 ? 0 : 4); + a[l+48] = (int8_t)((q3[l+0] >> 6) & 3) - (hm[l] & 0x40 ? 0 : 4); + a[l+56] = (int8_t)((q3[l+8] >> 6) & 3) - (hm[l] & 0x80 ? 0 : 4); + } + + scales[0] = (x[i].scales[0] & 0xF) - 8; + scales[1] = (x[i].scales[0] >> 4) - 8; + scales[2] = (x[i].scales[1] & 0xF) - 8; + scales[3] = (x[i].scales[1] >> 4) - 8; + + memset(aux32, 0, 8*sizeof(int32_t)); + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] += q8[l] * a[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux32[l] += scales[j] * aux16[l]; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; + +#endif + +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q4_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q4_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + + static const uint32_t kmask1 = 0x3f3f3f3f; + static const uint32_t kmask2 = 0x0f0f0f0f; + static const uint32_t kmask3 = 0x03030303; + + uint32_t utmp[4]; + +#ifdef __ARM_NEON + const uint8x16_t m4b = vdupq_n_u8(0xf); + const int32x4_t mzero = vdupq_n_s32(0); + + ggml_int8x16x2_t q4bytes; + ggml_int8x16x2_t q8bytes; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const int16x8_t q8sums = vpaddq_s16(vld1q_s16(y[i].bsums), vld1q_s16(y[i].bsums + 8)); + + memcpy(utmp, x[i].scales, 12); + + uint32x2_t mins8 = { 0 }; + mins8 = vset_lane_u32(utmp[1] & kmask1, mins8, 0); + mins8 = vset_lane_u32(((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4), mins8, 1); + + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[0] &= kmask1; + + const int16x8_t mins = vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(mins8))); + const int32x4_t prod = vaddq_s32(vmull_s16(vget_low_s16 (q8sums), vget_low_s16 (mins)), + vmull_s16(vget_high_s16(q8sums), vget_high_s16(mins))); + sumf -= dmin * vaddvq_s32(prod); + + const uint8_t * scales = (const uint8_t *)utmp; + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + int32_t sumi1 = 0; + int32_t sumi2 = 0; + + for (int j = 0; j < QK_K/64; ++j) { + const ggml_uint8x16x2_t q4bits = ggml_vld1q_u8_x2(q4); q4 += 32; + + q8bytes = ggml_vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + sumi1 += vaddvq_s32(p1) * scales[2*j+0]; + + q8bytes = ggml_vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + + sumi2 += vaddvq_s32(p2) * scales[2*j+1]; + } + + sumf += d * (sumi1 + sumi2); + + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + __m128 acc_m = _mm_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i mins_and_scales = _mm256_cvtepu8_epi16(_mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0])); + + const __m256i q8sums = _mm256_loadu_si256((const __m256i*)y[i].bsums); + const __m128i q8s = _mm_hadd_epi16(_mm256_extracti128_si256(q8sums, 0), _mm256_extracti128_si256(q8sums, 1)); + const __m128i prod = _mm_madd_epi16(_mm256_extracti128_si256(mins_and_scales, 1), q8s); + acc_m = _mm_fmadd_ps(_mm_set1_ps(dmin), _mm_cvtepi32_ps(prod), acc_m); + + const __m128i sc128 = _mm256_extracti128_si256(mins_and_scales, 0); + const __m256i scales = MM256_SET_M128I(sc128, sc128); + + __m256i sumi = _mm256_setzero_si256(); + + for (int j = 0; j < QK_K/64; ++j) { + + const __m256i scale_l = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+0)); + const __m256i scale_h = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+1)); + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4l = _mm256_and_si256(q4bits, m4); + const __m256i q4h = _mm256_and_si256(_mm256_srli_epi16(q4bits, 4), m4); + + const __m256i q8l = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + __m256i p16l = _mm256_maddubs_epi16(q4l, q8l); + p16l = _mm256_madd_epi16(scale_l, p16l); + + const __m256i q8h = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + __m256i p16h = _mm256_maddubs_epi16(q4h, q8h); + p16h = _mm256_madd_epi16(scale_h, p16h); + const __m256i sumj = _mm256_add_epi32(p16l, p16h); + + sumi = _mm256_add_epi32(sumi, sumj); + } + + __m256 vd = _mm256_set1_ps(d); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(sumi), acc); + + } + + acc_m = _mm_add_ps(acc_m, _mm_movehl_ps(acc_m, acc_m)); + acc_m = _mm_add_ss(acc_m, _mm_movehdup_ps(acc_m)); + + *s = hsum_float_8(acc) + _mm_cvtss_f32(acc_m); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(0x2); + + __m256 acc = _mm256_setzero_ps(); + __m128 acc_m = _mm_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const __m128i utmps = _mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0]); + const __m128i scales = _mm_cvtepu8_epi16(utmps); + const __m128i mins = _mm_cvtepu8_epi16(_mm_unpackhi_epi64(utmps, utmps)); + + const __m128i q8sums_0 = _mm_loadu_si128((const __m128i*)&y[i].bsums[0]); + const __m128i q8sums_1 = _mm_loadu_si128((const __m128i*)&y[i].bsums[8]); + const __m128i q8s = _mm_hadd_epi16(q8sums_0, q8sums_1); + const __m128i prod = _mm_madd_epi16(mins, q8s); + acc_m = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(dmin), _mm_cvtepi32_ps(prod)), acc_m); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + __m128i shuffle = _mm_set1_epi16(0x0100); + for (int j = 0; j < QK_K/64; ++j) { + + const __m128i scale_l = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + const __m128i scale_h = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + + __m128i q4bits = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4l_0 = _mm_and_si128(q4bits, m4); + const __m128i q4h_0 = _mm_and_si128(_mm_srli_epi16(q4bits, 4), m4); + q4bits = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4l_1 = _mm_and_si128(q4bits, m4); + const __m128i q4h_1 = _mm_and_si128(_mm_srli_epi16(q4bits, 4), m4); + + const __m128i q8l_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16l = _mm_maddubs_epi16(q4l_0, q8l_0); + p16l = _mm_madd_epi16(scale_l, p16l); + sumi_0 = _mm_add_epi32(sumi_0, p16l); + const __m128i q8l_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + p16l = _mm_maddubs_epi16(q4l_1, q8l_1); + p16l = _mm_madd_epi16(scale_l, p16l); + sumi_1 = _mm_add_epi32(sumi_1, p16l); + + const __m128i q8h_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16h = _mm_maddubs_epi16(q4h_0, q8h_0); + p16h = _mm_madd_epi16(scale_h, p16h); + sumi_0 = _mm_add_epi32(sumi_0, p16h); + const __m128i q8h_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + p16h = _mm_maddubs_epi16(q4h_1, q8h_1); + p16h = _mm_madd_epi16(scale_h, p16h); + sumi_1 = _mm_add_epi32(sumi_1, p16h); + + } + + __m256 vd = _mm256_set1_ps(d); + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(sumi)), acc); + + } + + acc_m = _mm_add_ps(acc_m, _mm_movehl_ps(acc_m, acc_m)); + acc_m = _mm_add_ss(acc_m, _mm_movehdup_ps(acc_m)); + + *s = hsum_float_8(acc) + _mm_cvtss_f32(acc_m); + +#elif defined __riscv_v_intrinsic + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + size_t vl = 8; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + vint16mf2_t q8sums_0 = __riscv_vlse16_v_i16mf2(y[i].bsums, 4, vl); + vint16mf2_t q8sums_1 = __riscv_vlse16_v_i16mf2(y[i].bsums+1, 4, vl); + vint16mf2_t q8sums = __riscv_vadd_vv_i16mf2(q8sums_0, q8sums_1, vl); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + vuint8mf4_t mins8 = __riscv_vle8_v_u8mf4(mins, vl); + vint16mf2_t v_mins = __riscv_vreinterpret_v_u16mf2_i16mf2(__riscv_vzext_vf2_u16mf2(mins8, vl)); + vint32m1_t prod = __riscv_vwmul_vv_i32m1(q8sums, v_mins, vl); + + vint32m1_t sumi = __riscv_vredsum_vs_i32m1_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + sumf -= dmin * __riscv_vmv_x_s_i32m1_i32(sumi); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + vl = 32; + + int32_t sum_1 = 0; + int32_t sum_2 = 0; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + for (int j = 0; j < QK_K/64; ++j) { + // load Q4 + vuint8m1_t q4_x = __riscv_vle8_v_u8m1(q4, vl); + + // load Q8 and multiply it with lower Q4 nibble + vint8m1_t q8_0 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q4_0 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q4_x, 0x0F, vl)); + vint16m2_t qv_0 = __riscv_vwmul_vv_i16m2(q4_0, q8_0, vl); + vint16m1_t vs_0 = __riscv_vredsum_vs_i16m2_i16m1(qv_0, vzero, vl); + + sum_1 += __riscv_vmv_x_s_i16m1_i16(vs_0) * scales[2*j+0]; + + // load Q8 and multiply it with upper Q4 nibble + vint8m1_t q8_1 = __riscv_vle8_v_i8m1(q8+32, vl); + vint8m1_t q4_1 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q4_x, 0x04, vl)); + vint16m2_t qv_1 = __riscv_vwmul_vv_i16m2(q4_1, q8_1, vl); + vint16m1_t vs_1 = __riscv_vredsum_vs_i16m2_i16m1(qv_1, vzero, vl); + + sum_2 += __riscv_vmv_x_s_i16m1_i16(vs_1) * scales[2*j+1]; + + q4 += 32; q8 += 64; + + } + + sumf += d*(sum_1 + sum_2); + + } + + *s = sumf; + +#else + + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int j = 0; j < QK_K/64; ++j) { + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] & 0xF); + a += 32; + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] >> 4); + a += 32; q4 += 32; + } + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + int sumi = 0; + for (int j = 0; j < QK_K/16; ++j) sumi += y[i].bsums[j] * mins[j/2]; + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/32; ++j) { + int32_t scale = scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + sumf -= dmin * sumi; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#else +void ggml_vec_dot_q4_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q4_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + const uint8x16_t m4b = vdupq_n_u8(0xf); + + const int32x4_t mzero = vdupq_n_s32(0); + + float sumf = 0; + + ggml_int8x16x2_t q4bytes; + ggml_int8x16x4_t q8bytes; + + float sum_mins = 0.f; + + uint16_t aux16[2]; + const uint8_t * restrict scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t * restrict a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + const int32_t summi = scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3]); + sum_mins += y[i].d * GGML_FP16_TO_FP32(x[i].d[1]) * summi; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d[0]); + + const ggml_uint8x16x2_t q4bits = ggml_vld1q_u8_x2(q4); + + q8bytes = ggml_vld1q_s8_x4(q8); + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + const int32_t sumi1 = vaddvq_s32(p1) * scales[0]; + + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[2]), q4bytes.val[1], q8bytes.val[3]); + const int32_t sumi2 = vaddvq_s32(p2) * scales[1]; + + sumf += d * (sumi1 + sumi2); + } + + *s = sumf - sum_mins; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + uint16_t aux16[2]; + const uint8_t * scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d[0]) * y[i].d; + const float m = GGML_FP16_TO_FP32(x[i].d[1]) * y[i].d; + const __m256 vd = _mm256_set1_ps(d); + + const uint16_t * a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + summs += m * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); + const __m256i q4l = _mm256_and_si256(q4bits, m4); + const __m256i q4h = _mm256_and_si256(_mm256_srli_epi16(q4bits, 4), m4); + + const __m256i q8l = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8h = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p16l = _mm256_maddubs_epi16(q4l, q8l); + const __m256i p16h = _mm256_maddubs_epi16(q4h, q8h); + + const __m256i p32l = _mm256_madd_epi16(_mm256_set1_epi16(scales[0]), p16l); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(p32l), acc); + + const __m256i p32h = _mm256_madd_epi16(_mm256_set1_epi16(scales[1]), p16h); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(p32h), acc); + + } + + *s = hsum_float_8(acc) - summs; + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + uint16_t aux16[2]; + const uint8_t * scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d[0]) * y[i].d; + const float m = GGML_FP16_TO_FP32(x[i].d[1]) * y[i].d; + const __m256 vd = _mm256_set1_ps(d); + + const uint16_t * a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + summs += m * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bits_0 = _mm256_extractf128_si256(q4bits, 0); + const __m128i q4bits_1 = _mm256_extractf128_si256(q4bits, 1); + const __m128i q4_0 = _mm_and_si128(q4bits_0, m4); + const __m128i q4_1 = _mm_and_si128(q4bits_1, m4); + const __m128i q4_2 = _mm_and_si128(_mm_srli_epi16(q4bits_0, 4), m4); + const __m128i q4_3 = _mm_and_si128(_mm_srli_epi16(q4bits_1, 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p16_0 = _mm_maddubs_epi16(q4_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i p16_1 = _mm_maddubs_epi16(q4_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i p16_2 = _mm_maddubs_epi16(q4_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i p16_3 = _mm_maddubs_epi16(q4_3, _mm256_extractf128_si256(q8_1, 1)); + + const __m128i p32_0 = _mm_madd_epi16(_mm_set1_epi16(scales[0]), p16_0); + const __m128i p32_1 = _mm_madd_epi16(_mm_set1_epi16(scales[0]), p16_1); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(MM256_SET_M128I(p32_1, p32_0))), acc); + + const __m128i p32_2 = _mm_madd_epi16(_mm_set1_epi16(scales[1]), p16_2); + const __m128i p32_3 = _mm_madd_epi16(_mm_set1_epi16(scales[1]), p16_3); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(MM256_SET_M128I(p32_3, p32_2))), acc); + + } + + *s = hsum_float_8(acc) - summs; + +#elif defined __riscv_v_intrinsic + + uint16_t s16[2]; + const uint8_t * restrict scales = (const uint8_t *)s16; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t * restrict b = (const uint16_t *)x[i].scales; + s16[0] = b[0] & 0x0f0f; + s16[1] = (b[0] >> 4) & 0x0f0f; + + sumf -= y[i].d * GGML_FP16_TO_FP32(x[i].d[1]) * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d[0]); + + size_t vl = 32; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + // load Q4 + vuint8m1_t q4_x = __riscv_vle8_v_u8m1(q4, vl); + + // load Q8 and multiply it with lower Q4 nibble + vint8m1_t q4_a = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q4_x, 0x0F, vl)); + vint16m2_t va_0 = __riscv_vwmul_vv_i16m2(q4_a, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m1_t aux1 = __riscv_vredsum_vs_i16m2_i16m1(va_0, vzero, vl); + + sumf += d*scales[0]*__riscv_vmv_x_s_i16m1_i16(aux1); + + // load Q8 and multiply it with upper Q4 nibble + vint8m1_t q4_s = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q4_x, 0x04, vl)); + vint16m2_t va_1 = __riscv_vwmul_vv_i16m2(q4_s, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m1_t aux2 = __riscv_vredsum_vs_i16m2_i16m1(va_1, vzero, vl); + + sumf += d*scales[1]*__riscv_vmv_x_s_i16m1_i16(aux2); + + } + + *s = sumf; + +#else + + uint8_t aux8[QK_K]; + int16_t aux16[16]; + float sums [8]; + memset(sums, 0, 8*sizeof(float)); + + uint16_t s16[2]; + const uint8_t * restrict scales = (const uint8_t *)s16; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + uint8_t * restrict a = aux8; + for (int l = 0; l < 32; ++l) a[l+ 0] = q4[l] & 0xF; + for (int l = 0; l < 32; ++l) a[l+32] = q4[l] >> 4; + + const uint16_t * restrict b = (const uint16_t *)x[i].scales; + s16[0] = b[0] & 0x0f0f; + s16[1] = (b[0] >> 4) & 0x0f0f; + + sumf -= y[i].d * GGML_FP16_TO_FP32(x[i].d[1]) * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d[0]); + + for (int j = 0; j < QK_K/32; ++j) { + for (int l = 0; l < 16; ++l) aux16[l] = q8[l] * a[l]; + q8 += 16; a += 16; + for (int l = 0; l < 16; ++l) aux16[l] += q8[l] * a[l]; + q8 += 16; a += 16; + const float dl = d * scales[j]; + for (int l = 0; l < 8; ++l) sums[l] += dl * (aux16[l] + aux16[l+8]); + } + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q5_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q5_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + + static const uint32_t kmask1 = 0x3f3f3f3f; + static const uint32_t kmask2 = 0x0f0f0f0f; + static const uint32_t kmask3 = 0x03030303; + + uint32_t utmp[4]; + +#ifdef __ARM_NEON + const uint8x16_t m4b = vdupq_n_u8(0xf); + const uint8x16_t mone = vdupq_n_u8(1); + const uint8x16_t mtwo = vdupq_n_u8(2); + const int32x4_t mzero = vdupq_n_s32(0); + + ggml_int8x16x4_t q5bytes; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const int16x8_t q8sums = vpaddq_s16(vld1q_s16(y[i].bsums), vld1q_s16(y[i].bsums + 8)); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const uint8x8_t mins8 = vld1_u8((const uint8_t*)utmp + 8); + const int16x8_t mins = vreinterpretq_s16_u16(vmovl_u8(mins8)); + const int32x4_t prod = vaddq_s32(vmull_s16(vget_low_s16 (q8sums), vget_low_s16 (mins)), + vmull_s16(vget_high_s16(q8sums), vget_high_s16(mins))); + int32_t sumi_mins = vaddvq_s32(prod); + + const uint8_t * scales = (const uint8_t *)utmp; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + ggml_uint8x16x2_t qhbits = ggml_vld1q_u8_x2(qh); + + ggml_uint8x16x4_t q5h; + + int32_t sumi = 0; + + for (int j = 0; j < QK_K/64; ++j) { + + const ggml_uint8x16x2_t q5bits = ggml_vld1q_u8_x2(q5); q5 += 32; + const ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(q8); q8 += 64; + + q5h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits.val[0]), 4); + q5h.val[1] = vshlq_n_u8(vandq_u8(mone, qhbits.val[1]), 4); + q5h.val[2] = vshlq_n_u8(vandq_u8(mtwo, qhbits.val[0]), 3); + q5h.val[3] = vshlq_n_u8(vandq_u8(mtwo, qhbits.val[1]), 3); + qhbits.val[0] = vshrq_n_u8(qhbits.val[0], 2); + qhbits.val[1] = vshrq_n_u8(qhbits.val[1], 2); + + q5bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q5bits.val[0], m4b), q5h.val[0])); + q5bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q5bits.val[1], m4b), q5h.val[1])); + q5bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q5bits.val[0], 4), q5h.val[2])); + q5bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q5bits.val[1], 4), q5h.val[3])); + + sumi += vaddvq_s32(ggml_vdotq_s32(ggml_vdotq_s32(mzero, q5bytes.val[0], q8bytes.val[0]), q5bytes.val[1], q8bytes.val[1])) * *scales++; + sumi += vaddvq_s32(ggml_vdotq_s32(ggml_vdotq_s32(mzero, q5bytes.val[2], q8bytes.val[2]), q5bytes.val[3], q8bytes.val[3])) * *scales++; + } + + sumf += d * sumi - dmin * sumi_mins; + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m128i mzero = _mm_setzero_si128(); + const __m256i mone = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.f; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + +#if QK_K == 256 + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; +#else + // TODO + const float d = 0, dmin = 0; +#endif + + const __m256i mins_and_scales = _mm256_cvtepu8_epi16(_mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0])); + + const __m256i q8sums = _mm256_loadu_si256((const __m256i*)y[i].bsums); + const __m128i q8s = _mm_hadd_epi16(_mm256_extracti128_si256(q8sums, 0), _mm256_extracti128_si256(q8sums, 1)); + const __m128i prod = _mm_madd_epi16(_mm256_extracti128_si256(mins_and_scales, 1), q8s); + const __m128i hsum = _mm_hadd_epi32(_mm_hadd_epi32(prod, mzero), mzero); + summs += dmin * _mm_extract_epi32(hsum, 0); + + const __m128i sc128 = _mm256_extracti128_si256(mins_and_scales, 0); + const __m256i scales = MM256_SET_M128I(sc128, sc128); + + const __m256i hbits = _mm256_loadu_si256((const __m256i*)x[i].qh); + __m256i hmask = mone; + + __m256i sumi = _mm256_setzero_si256(); + + int bit = 0; + + for (int j = 0; j < QK_K/64; ++j) { + + const __m256i scale_0 = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+0)); + const __m256i scale_1 = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+1)); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); q5 += 32; + + const __m256i q5l_0 = _mm256_and_si256(q5bits, m4); + const __m256i q5h_0 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_and_si256(hbits, hmask), bit++), 4); + const __m256i q5_0 = _mm256_add_epi8(q5l_0, q5h_0); + hmask = _mm256_slli_epi16(hmask, 1); + + const __m256i q5l_1 = _mm256_and_si256(_mm256_srli_epi16(q5bits, 4), m4); + const __m256i q5h_1 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_and_si256(hbits, hmask), bit++), 4); + const __m256i q5_1 = _mm256_add_epi8(q5l_1, q5h_1); + hmask = _mm256_slli_epi16(hmask, 1); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + __m256i p16_0 = _mm256_maddubs_epi16(q5_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q5_1, q8_1); + + p16_0 = _mm256_madd_epi16(scale_0, p16_0); + p16_1 = _mm256_madd_epi16(scale_1, p16_1); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + + } + + __m256 vd = _mm256_set1_ps(d); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i mzero = _mm_setzero_si128(); + const __m128i mone = _mm_set1_epi8(1); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.f; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const __m128i utmps = _mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0]); + const __m128i scales = _mm_cvtepu8_epi16(utmps); + const __m128i mins = _mm_cvtepu8_epi16(_mm_unpackhi_epi64(utmps, utmps)); + + const __m128i q8sums_0 = _mm_loadu_si128((const __m128i*)&y[i].bsums[0]); + const __m128i q8sums_1 = _mm_loadu_si128((const __m128i*)&y[i].bsums[8]); + const __m128i q8s = _mm_hadd_epi16(q8sums_0, q8sums_1); + const __m128i prod = _mm_madd_epi16(mins, q8s); + const __m128i hsum = _mm_hadd_epi32(_mm_hadd_epi32(prod, mzero), mzero); + summs += dmin * _mm_extract_epi32(hsum, 0); + + const __m128i hbits_0 = _mm_loadu_si128((const __m128i*)&x[i].qh[0]); + const __m128i hbits_1 = _mm_loadu_si128((const __m128i*)&x[i].qh[16]); + __m128i hmask = mone; + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + int bit = 0; + + __m128i shuffle = _mm_set1_epi16(0x0100); + for (int j = 0; j < QK_K/64; ++j) { + + const __m128i scale_0 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + const __m128i scale_1 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + + const __m128i q5bits_0 = _mm_loadu_si128((const __m128i*)q5); q5 += 16; + const __m128i q5bits_1 = _mm_loadu_si128((const __m128i*)q5); q5 += 16; + + __m128i q5l_0 = _mm_and_si128(q5bits_0, m4); + __m128i q5l_1 = _mm_and_si128(q5bits_1, m4); + __m128i q5h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_0, hmask), bit), 4); + __m128i q5h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_1, hmask), bit++), 4); + __m128i q5_0 = _mm_add_epi8(q5l_0, q5h_0); + __m128i q5_1 = _mm_add_epi8(q5l_1, q5h_1); + hmask = _mm_slli_epi16(hmask, 1); + + __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16_0 = _mm_maddubs_epi16(q5_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q5_1, q8_1); + p16_0 = _mm_madd_epi16(scale_0, p16_0); + p16_1 = _mm_madd_epi16(scale_0, p16_1); + + q5l_0 = _mm_and_si128(_mm_srli_epi16(q5bits_0, 4), m4); + q5l_1 = _mm_and_si128(_mm_srli_epi16(q5bits_1, 4), m4); + q5h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_0, hmask), bit), 4); + q5h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_1, hmask), bit++), 4); + q5_0 = _mm_add_epi8(q5l_0, q5h_0); + q5_1 = _mm_add_epi8(q5l_1, q5h_1); + hmask = _mm_slli_epi16(hmask, 1); + + q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16_2 = _mm_maddubs_epi16(q5_0, q8_0); + __m128i p16_3 = _mm_maddubs_epi16(q5_1, q8_1); + p16_2 = _mm_madd_epi16(scale_1, p16_2); + p16_3 = _mm_madd_epi16(scale_1, p16_3); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + + } + + __m256 vd = _mm256_set1_ps(d); + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(sumi)), acc); + + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __riscv_v_intrinsic + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + float sumf = 0; + float sums = 0.0; + + size_t vl; + + for (int i = 0; i < nb; ++i) { + + vl = 8; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + + vint16mf2_t q8sums_0 = __riscv_vlse16_v_i16mf2(y[i].bsums, 4, vl); + vint16mf2_t q8sums_1 = __riscv_vlse16_v_i16mf2(y[i].bsums+1, 4, vl); + vint16mf2_t q8sums = __riscv_vadd_vv_i16mf2(q8sums_0, q8sums_1, vl); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + vuint8mf4_t mins8 = __riscv_vle8_v_u8mf4(mins, vl); + vint16mf2_t v_mins = __riscv_vreinterpret_v_u16mf2_i16mf2(__riscv_vzext_vf2_u16mf2(mins8, vl)); + vint32m1_t prod = __riscv_vwmul_vv_i32m1(q8sums, v_mins, vl); + + vint32m1_t sumi = __riscv_vredsum_vs_i32m1_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + sumf -= dmin * __riscv_vmv_x_s_i32m1_i32(sumi); + + vl = 32; + int32_t aux32 = 0; + int is = 0; + + uint8_t m = 1; + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t vqh = __riscv_vle8_v_u8m1(hm, vl); + + for (int j = 0; j < QK_K/64; ++j) { + // load Q5 and Q8 + vuint8m1_t q5_x = __riscv_vle8_v_u8m1(q5, vl); + vint8m1_t q8_y1 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q8_y2 = __riscv_vle8_v_i8m1(q8+32, vl); + + // compute mask for addition + vint8m1_t q5_a = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q5_x, 0x0F, vl)); + vuint8m1_t qh_m1 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_1 = __riscv_vmsne_vx_u8m1_b8(qh_m1, 0, vl); + vint8m1_t q5_m1 = __riscv_vadd_vx_i8m1_m(vmask_1, q5_a, 16, vl); + m <<= 1; + + vint8m1_t q5_l = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q5_x, 0x04, vl)); + vuint8m1_t qh_m2 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_2 = __riscv_vmsne_vx_u8m1_b8(qh_m2, 0, vl); + vint8m1_t q5_m2 = __riscv_vadd_vx_i8m1_m(vmask_2, q5_l, 16, vl); + m <<= 1; + + vint16m2_t v0 = __riscv_vwmul_vv_i16m2(q5_m1, q8_y1, vl); + vint16m2_t v1 = __riscv_vwmul_vv_i16m2(q5_m2, q8_y2, vl); + + vint32m4_t vs1 = __riscv_vwmul_vx_i32m4(v0, scales[is++], vl); + vint32m4_t vs2 = __riscv_vwmul_vx_i32m4(v1, scales[is++], vl); + + vint32m1_t vacc1 = __riscv_vredsum_vs_i32m4_i32m1(vs1, vzero, vl); + vint32m1_t vacc2 = __riscv_vredsum_vs_i32m4_i32m1(vs2, vzero, vl); + + aux32 += __riscv_vmv_x_s_i32m1_i32(vacc1) + __riscv_vmv_x_s_i32m1_i32(vacc2); + q5 += 32; q8 += 64; + + } + + vfloat32m1_t vaux = __riscv_vfmul_vf_f32m1(__riscv_vfmv_v_f_f32m1(aux32, 1), d, 1); + sums += __riscv_vfmv_f_s_f32m1_f32(vaux); + + } + + *s = sumf+sums; + +#else + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + uint8_t m = 1; + for (int j = 0; j < QK_K/64; ++j) { + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] & 0xF); + for (int l = 0; l < 32; ++l) a[l] += (hm[l] & m ? 16 : 0); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] >> 4); + for (int l = 0; l < 32; ++l) a[l] += (hm[l] & m ? 16 : 0); + a += 32; m <<= 1; + q4 += 32; + } + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + int sumi = 0; + for (int j = 0; j < QK_K/16; ++j) sumi += y[i].bsums[j] * mins[j/2]; + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/32; ++j) { + int32_t scale = scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + sumf -= dmin * sumi; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q5_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q5_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + const uint8x16_t m4b = vdupq_n_u8(0xf); + const uint8x16_t mh = vdupq_n_u8(16); + const int32x4_t mzero = vdupq_n_s32(0); + + ggml_int8x16x4_t q5bytes; + ggml_uint8x16x4_t q5h; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const int8_t * sc = x[i].scales; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const uint8x8_t qhbits = vld1_u8(qh); + + const ggml_uint8x16x2_t q5bits = ggml_vld1q_u8_x2(q5); + const ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(q8); + + const uint8x16_t htmp = vcombine_u8(qhbits, vshr_n_u8(qhbits, 1)); + q5h.val[0] = vbicq_u8(mh, vshlq_n_u8(htmp, 4)); + q5h.val[1] = vbicq_u8(mh, vshlq_n_u8(htmp, 2)); + q5h.val[2] = vbicq_u8(mh, htmp); + q5h.val[3] = vbicq_u8(mh, vshrq_n_u8(htmp, 2)); + + q5bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q5bits.val[0], m4b)), vreinterpretq_s8_u8(q5h.val[0])); + q5bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q5bits.val[1], m4b)), vreinterpretq_s8_u8(q5h.val[1])); + q5bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vshrq_n_u8(q5bits.val[0], 4)), vreinterpretq_s8_u8(q5h.val[2])); + q5bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vshrq_n_u8(q5bits.val[1], 4)), vreinterpretq_s8_u8(q5h.val[3])); + + int32_t sumi1 = sc[0] * vaddvq_s32(ggml_vdotq_s32(mzero, q5bytes.val[0], q8bytes.val[0])); + int32_t sumi2 = sc[1] * vaddvq_s32(ggml_vdotq_s32(mzero, q5bytes.val[1], q8bytes.val[1])); + int32_t sumi3 = sc[2] * vaddvq_s32(ggml_vdotq_s32(mzero, q5bytes.val[2], q8bytes.val[2])); + int32_t sumi4 = sc[3] * vaddvq_s32(ggml_vdotq_s32(mzero, q5bytes.val[3], q8bytes.val[3])); + + sumf += d * (sumi1 + sumi2 + sumi3 + sumi4); + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i mone = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); + + const __m256i scale_l = MM256_SET_M128I(_mm_set1_epi16(x[i].scales[1]), _mm_set1_epi16(x[i].scales[0])); + const __m256i scale_h = MM256_SET_M128I(_mm_set1_epi16(x[i].scales[3]), _mm_set1_epi16(x[i].scales[2])); + + int64_t aux64; + memcpy(&aux64, x[i].qh, 8); + const __m128i haux128 = _mm_set_epi64x(aux64 >> 1, aux64); + const __m256i haux256 = MM256_SET_M128I(_mm_srli_epi16(haux128, 2), haux128); + + const __m256i q5h_0 = _mm256_slli_epi16(_mm256_andnot_si256(haux256, mone), 4); + const __m256i q5h_1 = _mm256_slli_epi16(_mm256_andnot_si256(_mm256_srli_epi16(haux256, 4), mone), 4); + + const __m256i q5l_0 = _mm256_and_si256(q5bits, m4); + const __m256i q5l_1 = _mm256_and_si256(_mm256_srli_epi16(q5bits, 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p16_0 = _mm256_madd_epi16(scale_l, _mm256_maddubs_epi16(q5l_0, q8_0)); + const __m256i p16_1 = _mm256_madd_epi16(scale_h, _mm256_maddubs_epi16(q5l_1, q8_1)); + const __m256i s16_0 = _mm256_madd_epi16(scale_l, _mm256_maddubs_epi16(q5h_0, q8_0)); + const __m256i s16_1 = _mm256_madd_epi16(scale_h, _mm256_maddubs_epi16(q5h_1, q8_1)); + + const __m256i dot = _mm256_sub_epi32(_mm256_add_epi32(p16_0, p16_1), _mm256_add_epi32(s16_0, s16_1)); + + acc = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(dot), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i mone = _mm_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); + + const __m128i scale_0 = _mm_set1_epi16(x[i].scales[0]); + const __m128i scale_1 = _mm_set1_epi16(x[i].scales[1]); + const __m128i scale_2 = _mm_set1_epi16(x[i].scales[2]); + const __m128i scale_3 = _mm_set1_epi16(x[i].scales[3]); + + int64_t aux64; + memcpy(&aux64, x[i].qh, 8); + const __m128i haux128_0 = _mm_set_epi64x(aux64 >> 1, aux64); + const __m128i haux128_1 = _mm_srli_epi16(haux128_0, 2); + + const __m128i q5h_0 = _mm_slli_epi16(_mm_andnot_si128(haux128_0, mone), 4); + const __m128i q5h_1 = _mm_slli_epi16(_mm_andnot_si128(haux128_1, mone), 4); + const __m128i q5h_2 = _mm_slli_epi16(_mm_andnot_si128(_mm_srli_epi16(haux128_0, 4), mone), 4); + const __m128i q5h_3 = _mm_slli_epi16(_mm_andnot_si128(_mm_srli_epi16(haux128_1, 4), mone), 4); + + const __m128i q5l_0 = _mm_and_si128(_mm256_extractf128_si256(q5bits, 0), m4); + const __m128i q5l_1 = _mm_and_si128(_mm256_extractf128_si256(q5bits, 1), m4); + const __m128i q5l_2 = _mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q5bits, 0), 4), m4); + const __m128i q5l_3 = _mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q5bits, 1), 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p16_0 = _mm_madd_epi16(scale_0, _mm_maddubs_epi16(q5l_0, _mm256_extractf128_si256(q8_0, 0))); + const __m128i p16_1 = _mm_madd_epi16(scale_1, _mm_maddubs_epi16(q5l_1, _mm256_extractf128_si256(q8_0, 1))); + const __m128i p16_2 = _mm_madd_epi16(scale_2, _mm_maddubs_epi16(q5l_2, _mm256_extractf128_si256(q8_1, 0))); + const __m128i p16_3 = _mm_madd_epi16(scale_3, _mm_maddubs_epi16(q5l_3, _mm256_extractf128_si256(q8_1, 1))); + const __m128i s16_0 = _mm_madd_epi16(scale_0, _mm_maddubs_epi16(q5h_0, _mm256_extractf128_si256(q8_0, 0))); + const __m128i s16_1 = _mm_madd_epi16(scale_1, _mm_maddubs_epi16(q5h_1, _mm256_extractf128_si256(q8_0, 1))); + const __m128i s16_2 = _mm_madd_epi16(scale_2, _mm_maddubs_epi16(q5h_2, _mm256_extractf128_si256(q8_1, 0))); + const __m128i s16_3 = _mm_madd_epi16(scale_3, _mm_maddubs_epi16(q5h_3, _mm256_extractf128_si256(q8_1, 1))); + + const __m128i dot_0 = _mm_sub_epi32(_mm_add_epi32(p16_0, p16_2), _mm_add_epi32(s16_0, s16_2)); + const __m128i dot_1 = _mm_sub_epi32(_mm_add_epi32(p16_1, p16_3), _mm_add_epi32(s16_1, s16_3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(MM256_SET_M128I(dot_1, dot_0))), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const int8_t * sc = x[i].scales; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load qh + vuint8mf4_t qh_x1 = __riscv_vle8_v_u8mf4(qh, 8); + vuint8mf2_t qh_x2 = __riscv_vlmul_ext_v_u8mf4_u8mf2(__riscv_vsrl_vx_u8mf4(qh_x1, 1, 8)); + + size_t vl = 16; + + // combine both qh_1 and qh_2 + vuint8mf2_t qh_x = __riscv_vslideup_vx_u8mf2(__riscv_vlmul_ext_v_u8mf4_u8mf2(qh_x1), qh_x2, vl/2, vl); + + vuint8mf2_t qh_h0 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x4, vl), vl), 16, vl); + vuint8mf2_t qh_h1 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x2, vl), vl), 16, vl); + vuint8mf2_t qh_h2 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(qh_x, vl), 16, vl); + vuint8mf2_t qh_h3 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x4, vl), vl), 16, vl); + + vint8mf2_t qh_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h0); + vint8mf2_t qh_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h1); + vint8mf2_t qh_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h2); + vint8mf2_t qh_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h3); + + // load q5 + vuint8mf2_t q5_x1 = __riscv_vle8_v_u8mf2(q5, vl); + vuint8mf2_t q5_x2 = __riscv_vle8_v_u8mf2(q5+16, vl); + + vint8mf2_t q5s_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q5_x1, 0xF, vl)); + vint8mf2_t q5s_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q5_x2, 0xF, vl)); + vint8mf2_t q5s_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vsrl_vx_u8mf2(q5_x1, 0x4, vl)); + vint8mf2_t q5s_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vsrl_vx_u8mf2(q5_x2, 0x4, vl)); + + vint8mf2_t q5_0 = __riscv_vsub_vv_i8mf2(q5s_0, qh_0, vl); + vint8mf2_t q5_1 = __riscv_vsub_vv_i8mf2(q5s_1, qh_1, vl); + vint8mf2_t q5_2 = __riscv_vsub_vv_i8mf2(q5s_2, qh_2, vl); + vint8mf2_t q5_3 = __riscv_vsub_vv_i8mf2(q5s_3, qh_3, vl); + + // load Q8 and multiply it with Q5 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q5_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q5_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q5_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q5_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + int32_t sumi1 = sc[0] * __riscv_vmv_x_s_i32m1_i32(vs_0); + int32_t sumi2 = sc[1] * __riscv_vmv_x_s_i32m1_i32(vs_1); + int32_t sumi3 = sc[2] * __riscv_vmv_x_s_i32m1_i32(vs_2); + int32_t sumi4 = sc[3] * __riscv_vmv_x_s_i32m1_i32(vs_3); + + sumf += d * (sumi1 + sumi2 + sumi3 + sumi4); + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[16]; + float sums [8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + int8_t * restrict a = aux8; + for (int l = 0; l < 32; ++l) { + a[l+ 0] = q4[l] & 0xF; + a[l+32] = q4[l] >> 4; + } + for (int is = 0; is < 8; ++is) { + uint8_t m = 1 << is; + for (int l = 0; l < 8; ++l) a[8*is + l] -= (hm[l] & m ? 0 : 16); + } + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const int8_t * restrict sc = x[i].scales; + + for (int j = 0; j < QK_K/16; ++j) { + const float dl = d * sc[j]; + for (int l = 0; l < 16; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) sums[l] += dl * (aux16[l] + aux16[8+l]); + q8 += 16; a += 16; + } + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#endif + + +#if QK_K == 256 +void ggml_vec_dot_q6_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q6_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + float sum = 0; + + const uint8x16_t m4b = vdupq_n_u8(0xF); + const int32x4_t vzero = vdupq_n_s32(0); + //const int8x16_t m32s = vdupq_n_s8(32); + + const uint8x16_t mone = vdupq_n_u8(3); + + ggml_int8x16x4_t q6bytes; + ggml_uint8x16x4_t q6h; + + for (int i = 0; i < nb; ++i) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + const ggml_int16x8x2_t q8sums = ggml_vld1q_s16_x2(y[i].bsums); + const int8x16_t scales = vld1q_s8(scale); + const ggml_int16x8x2_t q6scales = {{vmovl_s8(vget_low_s8(scales)), vmovl_s8(vget_high_s8(scales))}}; + + const int32x4_t prod = vaddq_s32(vaddq_s32(vmull_s16(vget_low_s16 (q8sums.val[0]), vget_low_s16 (q6scales.val[0])), + vmull_s16(vget_high_s16(q8sums.val[0]), vget_high_s16(q6scales.val[0]))), + vaddq_s32(vmull_s16(vget_low_s16 (q8sums.val[1]), vget_low_s16 (q6scales.val[1])), + vmull_s16(vget_high_s16(q8sums.val[1]), vget_high_s16(q6scales.val[1])))); + int32_t isum_mins = vaddvq_s32(prod); + + int32_t isum = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + ggml_uint8x16x2_t qhbits = ggml_vld1q_u8_x2(qh); qh += 32; + ggml_uint8x16x4_t q6bits = ggml_vld1q_u8_x4(q6); q6 += 64; + ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(q8); q8 += 64; + + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits.val[0]), 4); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, qhbits.val[1]), 4); + uint8x16_t shifted = vshrq_n_u8(qhbits.val[0], 2); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 2); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + //q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])), m32s); + //q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])), m32s); + //q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[2], m4b), q6h.val[2])), m32s); + //q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[3], m4b), q6h.val[3])), m32s); + q6bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])); + q6bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])); + q6bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[2], m4b), q6h.val[2])); + q6bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[3], m4b), q6h.val[3])); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; + + scale += 4; + + q8bytes = ggml_vld1q_s8_x4(q8); q8 += 64; + + shifted = vshrq_n_u8(qhbits.val[0], 4); + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 4); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[0], 6); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 6); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + //q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[0])), m32s); + //q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[1])), m32s); + //q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[2], 4), q6h.val[2])), m32s); + //q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[3], 4), q6h.val[3])), m32s); + q6bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[0])); + q6bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[1])); + q6bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[2], 4), q6h.val[2])); + q6bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[3], 4), q6h.val[3])); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; + scale += 4; + } + //sum += isum * d_all * y[i].d; + sum += d_all * y[i].d * (isum - 32 * isum_mins); + + } + *s = sum; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i m2 = _mm256_set1_epi8(3); + const __m256i m32s = _mm256_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m128i scales = _mm_loadu_si128((const __m128i*)x[i].scales); + + __m256i sumi = _mm256_setzero_si256(); + + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + const __m128i scale_0 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 0)); + const __m128i scale_1 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 1)); + const __m128i scale_2 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 2)); + const __m128i scale_3 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 3)); + is += 4; + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4bits2 = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4bitsH = _mm256_loadu_si256((const __m256i*)qh); qh += 32; + + const __m256i q4h_0 = _mm256_slli_epi16(_mm256_and_si256(q4bitsH, m2), 4); + const __m256i q4h_1 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 2), m2), 4); + const __m256i q4h_2 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 4), m2), 4); + const __m256i q4h_3 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 6), m2), 4); + + const __m256i q4_0 = _mm256_or_si256(_mm256_and_si256(q4bits1, m4), q4h_0); + const __m256i q4_1 = _mm256_or_si256(_mm256_and_si256(q4bits2, m4), q4h_1); + const __m256i q4_2 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits1, 4), m4), q4h_2); + const __m256i q4_3 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits2, 4), m4), q4h_3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + __m256i q8s_0 = _mm256_maddubs_epi16(m32s, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(m32s, q8_1); + __m256i q8s_2 = _mm256_maddubs_epi16(m32s, q8_2); + __m256i q8s_3 = _mm256_maddubs_epi16(m32s, q8_3); + + __m256i p16_0 = _mm256_maddubs_epi16(q4_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q4_1, q8_1); + __m256i p16_2 = _mm256_maddubs_epi16(q4_2, q8_2); + __m256i p16_3 = _mm256_maddubs_epi16(q4_3, q8_3); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + p16_2 = _mm256_sub_epi16(p16_2, q8s_2); + p16_3 = _mm256_sub_epi16(p16_3, q8s_3); + + p16_0 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_1), p16_1); + p16_2 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_2), p16_2); + p16_3 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_3), p16_3); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_2, p16_3)); + + } + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m3 = _mm_set1_epi8(3); + const __m128i m32s = _mm_set1_epi8(32); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m128i scales = _mm_loadu_si128((const __m128i*)x[i].scales); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + __m128i shuffle = _mm_set_epi64x(0x0101010101010101, 0x0000000000000000); + for (int j = 0; j < QK_K/128; ++j) { + + const __m128i q4bitsH_0 = _mm_loadu_si128((const __m128i*)qh); qh += 16; + const __m128i q4bitsH_1 = _mm_loadu_si128((const __m128i*)qh); qh += 16; + + const __m128i q4h_0 = _mm_slli_epi16(_mm_and_si128(q4bitsH_0, m3), 4); + const __m128i q4h_1 = _mm_slli_epi16(_mm_and_si128(q4bitsH_1, m3), 4); + const __m128i q4h_2 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 2), m3), 4); + const __m128i q4h_3 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 2), m3), 4); + const __m128i q4h_4 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 4), m3), 4); + const __m128i q4h_5 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 4), m3), 4); + const __m128i q4h_6 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 6), m3), 4); + const __m128i q4h_7 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 6), m3), 4); + + const __m128i q4bits1_0 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits1_1 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits2_0 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits2_1 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + + const __m128i q4_0 = _mm_or_si128(_mm_and_si128(q4bits1_0, m4), q4h_0); + const __m128i q4_1 = _mm_or_si128(_mm_and_si128(q4bits1_1, m4), q4h_1); + const __m128i q4_2 = _mm_or_si128(_mm_and_si128(q4bits2_0, m4), q4h_2); + const __m128i q4_3 = _mm_or_si128(_mm_and_si128(q4bits2_1, m4), q4h_3); + const __m128i q4_4 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits1_0, 4), m4), q4h_4); + const __m128i q4_5 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits1_1, 4), m4), q4h_5); + const __m128i q4_6 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits2_0, 4), m4), q4h_6); + const __m128i q4_7 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits2_1, 4), m4), q4h_7); + + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + __m128i q8s_0 = _mm_maddubs_epi16(m32s, q8_0); + __m128i q8s_1 = _mm_maddubs_epi16(m32s, q8_1); + __m128i q8s_2 = _mm_maddubs_epi16(m32s, q8_2); + __m128i q8s_3 = _mm_maddubs_epi16(m32s, q8_3); + __m128i q8s_4 = _mm_maddubs_epi16(m32s, q8_4); + __m128i q8s_5 = _mm_maddubs_epi16(m32s, q8_5); + __m128i q8s_6 = _mm_maddubs_epi16(m32s, q8_6); + __m128i q8s_7 = _mm_maddubs_epi16(m32s, q8_7); + + __m128i p16_0 = _mm_maddubs_epi16(q4_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q4_1, q8_1); + __m128i p16_2 = _mm_maddubs_epi16(q4_2, q8_2); + __m128i p16_3 = _mm_maddubs_epi16(q4_3, q8_3); + __m128i p16_4 = _mm_maddubs_epi16(q4_4, q8_4); + __m128i p16_5 = _mm_maddubs_epi16(q4_5, q8_5); + __m128i p16_6 = _mm_maddubs_epi16(q4_6, q8_6); + __m128i p16_7 = _mm_maddubs_epi16(q4_7, q8_7); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + p16_4 = _mm_sub_epi16(p16_4, q8s_4); + p16_5 = _mm_sub_epi16(p16_5, q8s_5); + p16_6 = _mm_sub_epi16(p16_6, q8s_6); + p16_7 = _mm_sub_epi16(p16_7, q8s_7); + + const __m128i scale_0 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_1 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_2 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_3 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + + p16_0 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_0, scale_0)), p16_1); + p16_2 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_1), p16_2); + p16_3 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_1, scale_1)), p16_3); + p16_4 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_2), p16_4); + p16_5 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_2, scale_2)), p16_5); + p16_6 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_3), p16_6); + p16_7 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_3, scale_3)), p16_7); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_4, p16_6)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_5, p16_7)); + + } + + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi)), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + size_t vl; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + int sum_t = 0; + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + vl = 32; + + // load qh + vuint8m1_t qh_x = __riscv_vle8_v_u8m1(qh, vl); + + // load Q6 + vuint8m1_t q6_0 = __riscv_vle8_v_u8m1(q6, vl); + vuint8m1_t q6_1 = __riscv_vle8_v_u8m1(q6+32, vl); + + vuint8m1_t q6a_0 = __riscv_vand_vx_u8m1(q6_0, 0x0F, vl); + vuint8m1_t q6a_1 = __riscv_vand_vx_u8m1(q6_1, 0x0F, vl); + vuint8m1_t q6s_0 = __riscv_vsrl_vx_u8m1(q6_0, 0x04, vl); + vuint8m1_t q6s_1 = __riscv_vsrl_vx_u8m1(q6_1, 0x04, vl); + + vuint8m1_t qh_0 = __riscv_vand_vx_u8m1(qh_x, 0x03, vl); + vuint8m1_t qh_1 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x2, vl), 0x03 , vl); + vuint8m1_t qh_2 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x4, vl), 0x03 , vl); + vuint8m1_t qh_3 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x6, vl), 0x03 , vl); + + vuint8m1_t qhi_0 = __riscv_vor_vv_u8m1(q6a_0, __riscv_vsll_vx_u8m1(qh_0, 0x04, vl), vl); + vuint8m1_t qhi_1 = __riscv_vor_vv_u8m1(q6a_1, __riscv_vsll_vx_u8m1(qh_1, 0x04, vl), vl); + vuint8m1_t qhi_2 = __riscv_vor_vv_u8m1(q6s_0, __riscv_vsll_vx_u8m1(qh_2, 0x04, vl), vl); + vuint8m1_t qhi_3 = __riscv_vor_vv_u8m1(q6s_1, __riscv_vsll_vx_u8m1(qh_3, 0x04, vl), vl); + + vint8m1_t a_0 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_0), 32, vl); + vint8m1_t a_1 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_1), 32, vl); + vint8m1_t a_2 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_2), 32, vl); + vint8m1_t a_3 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_3), 32, vl); + + // load Q8 and take product + vint16m2_t va_q_0 = __riscv_vwmul_vv_i16m2(a_0, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m2_t va_q_1 = __riscv_vwmul_vv_i16m2(a_1, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m2_t va_q_2 = __riscv_vwmul_vv_i16m2(a_2, __riscv_vle8_v_i8m1(q8+64, vl), vl); + vint16m2_t va_q_3 = __riscv_vwmul_vv_i16m2(a_3, __riscv_vle8_v_i8m1(q8+96, vl), vl); + + vl = 16; + + vint32m2_t vaux_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_0, 0), scale[is+0], vl); + vint32m2_t vaux_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_0, 1), scale[is+1], vl); + vint32m2_t vaux_2 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_1, 0), scale[is+2], vl); + vint32m2_t vaux_3 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_1, 1), scale[is+3], vl); + vint32m2_t vaux_4 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_2, 0), scale[is+4], vl); + vint32m2_t vaux_5 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_2, 1), scale[is+5], vl); + vint32m2_t vaux_6 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_3, 0), scale[is+6], vl); + vint32m2_t vaux_7 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_3, 1), scale[is+7], vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_0, vaux_1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_2, vaux_3, vl), isum0, vl); + vint32m1_t isum2 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_4, vaux_5, vl), isum1, vl); + vint32m1_t isum3 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_6, vaux_7, vl), isum2, vl); + + sum_t += __riscv_vmv_x_s_i32m1_i32(isum3); + + q6 += 64; qh += 32; q8 += 128; is=8; + + } + + sumf += d * sum_t; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + a[l + 0] = (int8_t)((q4[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + a[l + 32] = (int8_t)((q4[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + a[l + 64] = (int8_t)((q4[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + a[l + 96] = (int8_t)((q4[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + } + a += 128; + q4 += 64; + qh += 32; + } + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/16; ++j) { + int scale = x[i].scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q6_K_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_q6_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + float sum = 0; + + const uint8x16_t m4b = vdupq_n_u8(0xF); + const int8x16_t m32s = vdupq_n_s8(32); + const int32x4_t vzero = vdupq_n_s32(0); + + const uint8x16_t mone = vdupq_n_u8(3); + + ggml_int8x16x4_t q6bytes; + ggml_uint8x16x4_t q6h; + + for (int i = 0; i < nb; ++i) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + int32_t isum = 0; + + uint8x16_t qhbits = vld1q_u8(qh); + ggml_uint8x16x2_t q6bits = ggml_vld1q_u8_x2(q6); + ggml_int8x16x4_t q8bytes = ggml_vld1q_s8_x4(q8); + + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits), 4); + uint8x16_t shifted = vshrq_n_u8(qhbits, 2); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits, 4); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits, 6); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])), m32s); + q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])), m32s); + q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[2])), m32s); + q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[3])), m32s); + + isum += vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(ggml_vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; + + sum += isum * d_all * y[i].d; + + } + *s = sum; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i m2 = _mm256_set1_epi8(3); + const __m256i m32s = _mm256_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m64 scales_1 = _mm_set1_pi8(x[i].scales[0]); + const __m64 scales_2 = _mm_set1_pi8(x[i].scales[1]); + const __m64 scales_3 = _mm_set1_pi8(x[i].scales[2]); + const __m64 scales_4 = _mm_set1_pi8(x[i].scales[3]); + + __m256i sumi = _mm256_setzero_si256(); + + const __m128i scale_0 = _mm_set_epi64(scales_2, scales_1); + const __m128i scale_1 = _mm_set_epi64(scales_4, scales_3); + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bitsH = _mm_loadu_si128((const __m128i*)qh); + + const __m256i q4h_0 = _mm256_slli_epi16(_mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q4bitsH, 2), q4bitsH), m2), 4); + const __m256i q4h_1 = _mm256_slli_epi16(_mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q4bitsH, 6), _mm_srli_epi16(q4bitsH, 4)), m2), 4); + + const __m256i q4_0 = _mm256_or_si256(_mm256_and_si256(q4bits1, m4), q4h_0); + const __m256i q4_1 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits1, 4), m4), q4h_1); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + __m256i q8s_0 = _mm256_maddubs_epi16(m32s, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(m32s, q8_1); + + __m256i p16_0 = _mm256_maddubs_epi16(q4_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q4_1, q8_1); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + + p16_0 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_1), p16_1); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(3); + const __m128i m32s = _mm_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m64 scales_1 = _mm_set1_pi8(x[i].scales[0]); + const __m64 scales_2 = _mm_set1_pi8(x[i].scales[1]); + const __m64 scales_3 = _mm_set1_pi8(x[i].scales[2]); + const __m64 scales_4 = _mm_set1_pi8(x[i].scales[3]); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + const __m128i scale_0 = _mm_set_epi64(scales_2, scales_1); + const __m128i scale_1 = _mm_set_epi64(scales_4, scales_3); + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bitsH = _mm_loadu_si128((const __m128i*)qh); + + const __m128i q4h_0 = _mm_slli_epi16(_mm_and_si128(q4bitsH, m2), 4); + const __m128i q4h_1 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 2), m2), 4); + const __m128i q4h_2 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 4), m2), 4); + const __m128i q4h_3 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 6), m2), 4); + + const __m128i q4_0 = _mm_or_si128(_mm_and_si128(_mm256_extractf128_si256(q4bits1, 0), m4), q4h_0); + const __m128i q4_1 = _mm_or_si128(_mm_and_si128(_mm256_extractf128_si256(q4bits1, 1), m4), q4h_1); + const __m128i q4_2 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q4bits1, 0), 4), m4), q4h_2); + const __m128i q4_3 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q4bits1, 1), 4), m4), q4h_3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + __m128i q8s_0 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_0, 0)); + __m128i q8s_1 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_0, 1)); + __m128i q8s_2 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_1, 0)); + __m128i q8s_3 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_1, 1)); + + __m128i p16_0 = _mm_maddubs_epi16(q4_0, _mm256_extractf128_si256(q8_0, 0)); + __m128i p16_1 = _mm_maddubs_epi16(q4_1, _mm256_extractf128_si256(q8_0, 1)); + __m128i p16_2 = _mm_maddubs_epi16(q4_2, _mm256_extractf128_si256(q8_1, 0)); + __m128i p16_3 = _mm_maddubs_epi16(q4_3, _mm256_extractf128_si256(q8_1, 1)); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + + p16_0 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_0, scale_0)), p16_1); + p16_2 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_1), p16_2); + p16_3 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_1, scale_1)), p16_3); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(MM256_SET_M128I(sumi_1, sumi_0))), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + int32_t isum = 0; + + size_t vl = 16; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load Q6 + vuint8mf2_t q6_0 = __riscv_vle8_v_u8mf2(q6, vl); + vuint8mf2_t q6_1 = __riscv_vle8_v_u8mf2(q6+16, vl); + + // load qh + vuint8mf2_t qh_x = __riscv_vle8_v_u8mf2(qh, vl); + + vuint8mf2_t qh0 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh1 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh2 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh3 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + + vuint8mf2_t q6h_0 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q6_0, 0xF, vl), qh0, vl); + vuint8mf2_t q6h_1 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q6_1, 0xF, vl), qh1, vl); + vuint8mf2_t q6h_2 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q6_0, 0x4, vl), qh2, vl); + vuint8mf2_t q6h_3 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q6_1, 0x4, vl), qh3, vl); + + vint8mf2_t q6v_0 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_0), 32, vl); + vint8mf2_t q6v_1 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_1), 32, vl); + vint8mf2_t q6v_2 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_2), 32, vl); + vint8mf2_t q6v_3 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_3), 32, vl); + + // load Q8 and take product + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q6v_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q6v_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q6v_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q6v_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(vs_0) * scale[0]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_1) * scale[1]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_2) * scale[2]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_3) * scale[3]; + + sumf += isum * d_all * y[i].d; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int l = 0; l < 16; ++l) { + a[l+ 0] = (int8_t)((q4[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + a[l+16] = (int8_t)((q4[l+16] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + a[l+32] = (int8_t)((q4[l+ 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + a[l+48] = (int8_t)((q4[l+16] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + } + int is = 0; + for (int j = 0; j < QK_K/16; ++j) { + int scale = x[i].scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#endif + +#if defined (__AVX2__) || defined (__ARM_NEON) +static const int8_t keven_signs_q2xs[1024] = { + 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, + 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, + 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, + 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, + 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, + 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, + 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, + 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, + 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, + 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, + 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, + 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, + 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, + 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, + 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, + 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, + 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, + 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, + 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, + 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, + 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, + 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, + 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, + 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, + 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, + 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, + 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, + 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, + 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, + 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, + 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, + 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, +}; +#endif + +void ggml_vec_dot_iq2_xxs_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq2_xxs * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined(__ARM_NEON) + + const uint64_t * signs64 = (const uint64_t *)keven_signs_q2xs; + + uint32_t aux32[4]; + const uint8_t * aux8 = (const uint8_t *)aux32; + + ggml_int8x16x4_t q2u; + ggml_int8x16x4_t q2s; + ggml_int8x16x4_t q8b; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + float sumf1 = 0, sumf2 = 0; + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + memcpy(aux32, q2, 4*sizeof(uint32_t)); q2 += 8; + q2u.val[0] = vcombine_s8(vld1_s8((const void *)(iq2xxs_grid + aux8[ 0])), vld1_s8((const void *)(iq2xxs_grid + aux8[ 1]))); + q2u.val[1] = vcombine_s8(vld1_s8((const void *)(iq2xxs_grid + aux8[ 2])), vld1_s8((const void *)(iq2xxs_grid + aux8[ 3]))); + q2u.val[2] = vcombine_s8(vld1_s8((const void *)(iq2xxs_grid + aux8[ 8])), vld1_s8((const void *)(iq2xxs_grid + aux8[ 9]))); + q2u.val[3] = vcombine_s8(vld1_s8((const void *)(iq2xxs_grid + aux8[10])), vld1_s8((const void *)(iq2xxs_grid + aux8[11]))); + q2s.val[0] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[1] >> 0) & 127))), vld1_s8((const void *)(signs64 + ((aux32[1] >> 7) & 127)))); + q2s.val[1] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[1] >> 14) & 127))), vld1_s8((const void *)(signs64 + ((aux32[1] >> 21) & 127)))); + q2s.val[2] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[3] >> 0) & 127))), vld1_s8((const void *)(signs64 + ((aux32[3] >> 7) & 127)))); + q2s.val[3] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[3] >> 14) & 127))), vld1_s8((const void *)(signs64 + ((aux32[3] >> 21) & 127)))); + q2u.val[0] = vmulq_s8(q2u.val[0], q2s.val[0]); + q2u.val[1] = vmulq_s8(q2u.val[1], q2s.val[1]); + q2u.val[2] = vmulq_s8(q2u.val[2], q2s.val[2]); + q2u.val[3] = vmulq_s8(q2u.val[3], q2s.val[3]); + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[0], q8b.val[0]), q2u.val[1], q8b.val[1]); + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[2], q8b.val[2]), q2u.val[3], q8b.val[3]); + sumf1 += vaddvq_s32(p1) * (0.5f + (aux32[1] >> 28)); + sumf2 += vaddvq_s32(p2) * (0.5f + (aux32[3] >> 28)); + } + sumf += d*(sumf1 + sumf2); + } + *s = 0.25f * sumf; + +#elif defined(__AVX2__) + + const uint64_t * signs64 = (const uint64_t *)keven_signs_q2xs; + + uint32_t aux32[4]; + const uint8_t * aux8 = (const uint8_t *)aux32; + + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + memcpy(aux32, q2, 4*sizeof(uint32_t)); q2 += 8; + const __m256i q2_1 = _mm256_set_epi64x(iq2xxs_grid[aux8[ 3]], iq2xxs_grid[aux8[ 2]], iq2xxs_grid[aux8[1]], iq2xxs_grid[aux8[0]]); + const __m256i q2_2 = _mm256_set_epi64x(iq2xxs_grid[aux8[11]], iq2xxs_grid[aux8[10]], iq2xxs_grid[aux8[9]], iq2xxs_grid[aux8[8]]); + const __m256i s2_1 = _mm256_set_epi64x(signs64[(aux32[1] >> 21) & 127], signs64[(aux32[1] >> 14) & 127], + signs64[(aux32[1] >> 7) & 127], signs64[(aux32[1] >> 0) & 127]); + const __m256i s2_2 = _mm256_set_epi64x(signs64[(aux32[3] >> 21) & 127], signs64[(aux32[3] >> 14) & 127], + signs64[(aux32[3] >> 7) & 127], signs64[(aux32[3] >> 0) & 127]); + const __m256i q8s_1 = _mm256_sign_epi8(q8_1, s2_1); + const __m256i q8s_2 = _mm256_sign_epi8(q8_2, s2_2); + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); + const uint16_t ls1 = aux32[1] >> 28; + const uint16_t ls2 = aux32[3] >> 28; + const __m256i p1 = _mm256_madd_epi16(dot1, _mm256_set1_epi16(2*ls1+1)); + const __m256i p2 = _mm256_madd_epi16(dot2, _mm256_set1_epi16(2*ls2+1)); + sumi1 = _mm256_add_epi32(sumi1, p1); + sumi2 = _mm256_add_epi32(sumi2, p2); + } + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accumf); + + } + + *s = 0.125f * hsum_float_8(accumf); + +#else + + uint32_t aux32[2]; + const uint8_t * aux8 = (const uint8_t *)aux32; + + float sumf = 0.f; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + int32_t bsum = 0; + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + memcpy(aux32, q2, 2*sizeof(uint32_t)); + q2 += 4; + const uint32_t ls = 2*(aux32[1] >> 28) + 1; + int32_t sumi = 0; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2xxs_grid + aux8[l]); + const uint8_t signs = ksigns_iq2xs[(aux32[1] >> 7*l) & 127]; + for (int j = 0; j < 8; ++j) { + sumi += grid[j] * q8[j] * (signs & kmask_iq2xs[j] ? -1 : 1); + } + q8 += 8; + } + bsum += sumi * ls; + } + sumf += d * bsum; + } + *s = 0.125f * sumf; +#endif +} + +void ggml_vec_dot_iq2_xs_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq2_xs * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined(__ARM_NEON) + + const uint64_t * signs64 = (const uint64_t *)keven_signs_q2xs; + + ggml_int8x16x4_t q2u; + ggml_int8x16x4_t q2s; + ggml_int8x16x4_t q8b; + + int32x4x4_t scales32; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint8x8_t scales8 = vld1_u8(x[i].scales); + const uint8x8_t scales_l = vand_u8(scales8, vdup_n_u8(0xf)); + const uint8x8_t scales_h = vshr_n_u8(scales8, 4); + uint8x16_t scales = vcombine_u8(vzip1_u8(scales_l, scales_h), vzip2_u8(scales_l, scales_h)); + scales = vaddq_u8(vshlq_n_u8(scales, 1), vdupq_n_u8(1)); + const uint16x8_t scales1 = vmovl_u8(vget_low_u8(scales)); + const uint16x8_t scales2 = vmovl_u8(vget_high_u8(scales)); + scales32.val[0] = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(scales1))); + scales32.val[1] = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(scales1))); + scales32.val[2] = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(scales2))); + scales32.val[3] = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(scales2))); + int32x4_t sumi = vdupq_n_s32(0); + for (int ib64 = 0; ib64 < QK_K/64; ++ib64) { + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + q2u.val[0] = vcombine_s8(vld1_s8((const void *)(iq2xs_grid + (q2[0] & 511))), vld1_s8((const void *)(iq2xs_grid + (q2[1] & 511)))); + q2u.val[1] = vcombine_s8(vld1_s8((const void *)(iq2xs_grid + (q2[2] & 511))), vld1_s8((const void *)(iq2xs_grid + (q2[3] & 511)))); + q2u.val[2] = vcombine_s8(vld1_s8((const void *)(iq2xs_grid + (q2[4] & 511))), vld1_s8((const void *)(iq2xs_grid + (q2[5] & 511)))); + q2u.val[3] = vcombine_s8(vld1_s8((const void *)(iq2xs_grid + (q2[6] & 511))), vld1_s8((const void *)(iq2xs_grid + (q2[7] & 511)))); + q2s.val[0] = vcombine_s8(vld1_s8((const void *)(signs64 + (q2[0] >> 9))), vld1_s8((const void *)(signs64 + (q2[1] >> 9)))); + q2s.val[1] = vcombine_s8(vld1_s8((const void *)(signs64 + (q2[2] >> 9))), vld1_s8((const void *)(signs64 + (q2[3] >> 9)))); + q2s.val[2] = vcombine_s8(vld1_s8((const void *)(signs64 + (q2[4] >> 9))), vld1_s8((const void *)(signs64 + (q2[5] >> 9)))); + q2s.val[3] = vcombine_s8(vld1_s8((const void *)(signs64 + (q2[6] >> 9))), vld1_s8((const void *)(signs64 + (q2[7] >> 9)))); + q2u.val[0] = vmulq_s8(q2u.val[0], q2s.val[0]); + q2u.val[1] = vmulq_s8(q2u.val[1], q2s.val[1]); + q2u.val[2] = vmulq_s8(q2u.val[2], q2s.val[2]); + q2u.val[3] = vmulq_s8(q2u.val[3], q2s.val[3]); + const int32x4_t p1 = ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[0], q8b.val[0]); + const int32x4_t p2 = ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[1], q8b.val[1]); + const int32x4_t p3 = ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[2], q8b.val[2]); + const int32x4_t p4 = ggml_vdotq_s32(vdupq_n_s32(0), q2u.val[3], q8b.val[3]); + const int32x4_t p = vpaddq_s32(vpaddq_s32(p1, p2), vpaddq_s32(p3, p4)); + sumi = vmlaq_s32(sumi, p, scales32.val[ib64]); + q2 += 8; + } + sumf += d*vaddvq_s32(sumi); + } + *s = 0.125f * sumf; + +#elif defined(__AVX2__) + + const __m256i mone = _mm256_set1_epi8(1); + static const char block_sign_shuffle_mask_1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + }; + static const char block_sign_shuffle_mask_2[32] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + }; + static const uint8_t bit_selector_mask_bytes[32] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + }; + + const __m256i bit_selector_mask = _mm256_loadu_si256((const __m256i*)bit_selector_mask_bytes); + const __m256i block_sign_shuffle_1 = _mm256_loadu_si256((const __m256i*)block_sign_shuffle_mask_1); + const __m256i block_sign_shuffle_2 = _mm256_loadu_si256((const __m256i*)block_sign_shuffle_mask_2); + +#if QK_K == 64 + static const uint8_t k_bit_helper[16] = { + 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, + }; + const __m128i bit_helper = _mm_loadu_si128((const __m128i*)k_bit_helper); + const __m128i m511 = _mm_set1_epi16(511); + typedef union { + __m128i vec_index; + uint16_t index[8]; + } index_t; + + index_t idx; + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const __m128i q2_data = _mm_loadu_si128((const __m128i*)x[i].qs); + idx.vec_index = _mm_and_si128(q2_data, m511); + + const __m128i partial_sign_bits = _mm_srli_epi16(q2_data, 9); + const __m128i partial_sign_bits_upper = _mm_srli_epi16(q2_data, 13); + const __m128i partial_sign_bits_for_counting = _mm_xor_si128(partial_sign_bits, partial_sign_bits_upper); + + const __m128i odd_bits = _mm_shuffle_epi8(bit_helper, partial_sign_bits_for_counting); + const __m128i full_sign_bits = _mm_or_si128(partial_sign_bits, odd_bits); + const __m256i full_signs = MM256_SET_M128I(full_sign_bits, full_sign_bits); + + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)y[i].qs); + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)(y[i].qs+32)); + + const __m256i q2_1 = _mm256_set_epi64x(iq2xs_grid[idx.index[3]], iq2xs_grid[idx.index[2]], + iq2xs_grid[idx.index[1]], iq2xs_grid[idx.index[0]]); + const __m256i q2_2 = _mm256_set_epi64x(iq2xs_grid[idx.index[7]], iq2xs_grid[idx.index[6]], + iq2xs_grid[idx.index[5]], iq2xs_grid[idx.index[4]]); + + __m256i signs; + signs = _mm256_shuffle_epi8(full_signs, block_sign_shuffle_1); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_1 = _mm256_sign_epi8(q8_1, _mm256_or_si256(signs, mone)); + + signs = _mm256_shuffle_epi8(full_signs, block_sign_shuffle_2); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_2 = _mm256_sign_epi8(q8_2, _mm256_or_si256(signs, mone)); + + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); + + const __m256i sc1 = MM256_SET_M128I(_mm_set1_epi16(2*(x[i].scales[0] >> 4)+1), _mm_set1_epi16(2*(x[i].scales[0] & 0xf)+1)); + const __m256i sc2 = MM256_SET_M128I(_mm_set1_epi16(2*(x[i].scales[1] >> 4)+1), _mm_set1_epi16(2*(x[i].scales[1] & 0xf)+1)); + + const __m256i sum = _mm256_add_epi32(_mm256_madd_epi16(sc1, dot1), _mm256_madd_epi16(sc2, dot2)); + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(sum), accumf); + + } + + *s = 0.125f * hsum_float_8(accumf); +#else + + static const uint8_t k_bit_helper[32] = { + 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, + 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, + }; + const __m256i bit_helper = _mm256_loadu_si256((const __m256i*)k_bit_helper); + const __m256i m511 = _mm256_set1_epi16(511); + const __m128i m4 = _mm_set1_epi8(0xf); + const __m128i m1 = _mm_set1_epi8(1); + + uint64_t aux64; + + // somewhat hacky, but gives a significant boost in performance + __m256i aux_gindex; + const uint16_t * gindex = (const uint16_t *)&aux_gindex; + + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + memcpy(&aux64, x[i].scales, 8); + __m128i stmp = _mm_set1_epi64x(aux64); + stmp = _mm_unpacklo_epi8(_mm_and_si128(stmp, m4), _mm_and_si128(_mm_srli_epi16(stmp, 4), m4)); + const __m128i scales = _mm_add_epi8(_mm_slli_epi16(stmp, 1), m1); + + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 4) { + + const __m256i q2_data = _mm256_loadu_si256((const __m256i*)q2); q2 += 16; + aux_gindex = _mm256_and_si256(q2_data, m511); + + const __m256i partial_sign_bits = _mm256_srli_epi16(q2_data, 9); + const __m256i partial_sign_bits_upper = _mm256_srli_epi16(q2_data, 13); + const __m256i partial_sign_bits_for_counting = _mm256_xor_si256(partial_sign_bits, partial_sign_bits_upper); + + const __m256i odd_bits = _mm256_shuffle_epi8(bit_helper, partial_sign_bits_for_counting); + const __m256i full_sign_bits = _mm256_or_si256(partial_sign_bits, odd_bits); + + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_4 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + + const __m256i q2_1 = _mm256_set_epi64x(iq2xs_grid[gindex[ 3]], iq2xs_grid[gindex[ 2]], + iq2xs_grid[gindex[ 1]], iq2xs_grid[gindex[ 0]]); + const __m256i q2_2 = _mm256_set_epi64x(iq2xs_grid[gindex[ 7]], iq2xs_grid[gindex[ 6]], + iq2xs_grid[gindex[ 5]], iq2xs_grid[gindex[ 4]]); + const __m256i q2_3 = _mm256_set_epi64x(iq2xs_grid[gindex[11]], iq2xs_grid[gindex[10]], + iq2xs_grid[gindex[ 9]], iq2xs_grid[gindex[ 8]]); + const __m256i q2_4 = _mm256_set_epi64x(iq2xs_grid[gindex[15]], iq2xs_grid[gindex[14]], + iq2xs_grid[gindex[13]], iq2xs_grid[gindex[12]]); + + const __m128i full_signs_l = _mm256_castsi256_si128(full_sign_bits); + const __m128i full_signs_h = _mm256_extractf128_si256(full_sign_bits, 1); + const __m256i full_signs_1 = MM256_SET_M128I(full_signs_l, full_signs_l); + const __m256i full_signs_2 = MM256_SET_M128I(full_signs_h, full_signs_h); + + __m256i signs; + signs = _mm256_shuffle_epi8(full_signs_1, block_sign_shuffle_1); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_1 = _mm256_sign_epi8(q8_1, _mm256_or_si256(signs, mone)); + + signs = _mm256_shuffle_epi8(full_signs_1, block_sign_shuffle_2); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_2 = _mm256_sign_epi8(q8_2, _mm256_or_si256(signs, mone)); + + signs = _mm256_shuffle_epi8(full_signs_2, block_sign_shuffle_1); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_3 = _mm256_sign_epi8(q8_3, _mm256_or_si256(signs, mone)); + + signs = _mm256_shuffle_epi8(full_signs_2, block_sign_shuffle_2); + signs = _mm256_cmpeq_epi8(_mm256_and_si256(signs, bit_selector_mask), bit_selector_mask); + const __m256i q8s_4 = _mm256_sign_epi8(q8_4, _mm256_or_si256(signs, mone)); + + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); + const __m256i dot3 = _mm256_maddubs_epi16(q2_3, q8s_3); + const __m256i dot4 = _mm256_maddubs_epi16(q2_4, q8s_4); + + const __m256i sc1 = _mm256_cvtepi8_epi16(_mm_shuffle_epi8(scales, get_scale_shuffle(ib32+0))); + const __m256i sc2 = _mm256_cvtepi8_epi16(_mm_shuffle_epi8(scales, get_scale_shuffle(ib32+1))); + const __m256i sc3 = _mm256_cvtepi8_epi16(_mm_shuffle_epi8(scales, get_scale_shuffle(ib32+2))); + const __m256i sc4 = _mm256_cvtepi8_epi16(_mm_shuffle_epi8(scales, get_scale_shuffle(ib32+3))); + + sumi1 = _mm256_add_epi32(sumi1, _mm256_madd_epi16(dot1, sc1)); + sumi2 = _mm256_add_epi32(sumi2, _mm256_madd_epi16(dot2, sc2)); + sumi1 = _mm256_add_epi32(sumi1, _mm256_madd_epi16(dot3, sc3)); + sumi2 = _mm256_add_epi32(sumi2, _mm256_madd_epi16(dot4, sc4)); + } + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accumf); + + } + + *s = 0.125f * hsum_float_8(accumf); +#endif + +#else + + float sumf = 0.f; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint16_t * restrict q2 = x[i].qs; + const uint8_t * restrict sc = x[i].scales; + const int8_t * restrict q8 = y[i].qs; + int32_t bsum = 0; + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + const uint16_t ls1 = 2*(sc[ib32] & 0xf) + 1; + const uint16_t ls2 = 2*(sc[ib32] >> 4) + 1; + int32_t sumi = 0; + for (int l = 0; l < 2; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2xs_grid + (q2[l] & 511)); + const uint8_t signs = ksigns_iq2xs[q2[l] >> 9]; + for (int j = 0; j < 8; ++j) { + sumi += grid[j] * q8[j] * (signs & kmask_iq2xs[j] ? -1 : 1); + } + q8 += 8; + } + bsum += sumi * ls1; + sumi = 0; + for (int l = 2; l < 4; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2xs_grid + (q2[l] & 511)); + const uint8_t signs = ksigns_iq2xs[q2[l] >> 9]; + for (int j = 0; j < 8; ++j) { + sumi += grid[j] * q8[j] * (signs & kmask_iq2xs[j] ? -1 : 1); + } + q8 += 8; + } + bsum += sumi * ls2; + q2 += 4; + } + sumf += d * bsum; + } + *s = 0.125f * sumf; +#endif +} + +void ggml_vec_dot_iq2_s_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq2_s * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined(__ARM_NEON) + + static const uint8_t k_mask1[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 + }; + + static const uint8_t k_mask2[16] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,}; + + const ggml_uint8x16x2_t mask1 = ggml_vld1q_u8_x2(k_mask1); + const uint8x16_t mask2 = vld1q_u8(k_mask2); + const uint8x16_t m1 = vdupq_n_u8(1); + const int32x4_t vzero = vdupq_n_s32(0); + + uint8x16x2_t vs; + ggml_int8x16x4_t q2s; + ggml_int8x16x4_t q8b; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + + const uint8_t * restrict qs = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const uint16_t * restrict signs = (const uint16_t *)(x[i].qs + QK_K/8); + const int8_t * restrict q8 = y[i].qs; + + int sumi1 = 0, sumi2 = 0; + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + q2s.val[0] = vcombine_s8(vld1_s8((const int8_t *)(iq2s_grid + (qs[0] | ((qh[ib32+0] << 8) & 0x300)))), + vld1_s8((const int8_t *)(iq2s_grid + (qs[1] | ((qh[ib32+0] << 6) & 0x300))))); + q2s.val[1] = vcombine_s8(vld1_s8((const int8_t *)(iq2s_grid + (qs[2] | ((qh[ib32+0] << 4) & 0x300)))), + vld1_s8((const int8_t *)(iq2s_grid + (qs[3] | ((qh[ib32+0] << 2) & 0x300))))); + q2s.val[2] = vcombine_s8(vld1_s8((const int8_t *)(iq2s_grid + (qs[4] | ((qh[ib32+1] << 8) & 0x300)))), + vld1_s8((const int8_t *)(iq2s_grid + (qs[5] | ((qh[ib32+1] << 6) & 0x300))))); + q2s.val[3] = vcombine_s8(vld1_s8((const int8_t *)(iq2s_grid + (qs[6] | ((qh[ib32+1] << 4) & 0x300)))), + vld1_s8((const int8_t *)(iq2s_grid + (qs[7] | ((qh[ib32+1] << 2) & 0x300))))); + qs += 8; + + vs.val[0] = vreinterpretq_u8_u32(vdupq_n_u32(signs[0] | ((uint32_t) signs[1] << 16))); + vs.val[1] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[1]), mask2); + vs.val[0] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[0]), mask2); + vs.val[0] = vceqq_u8(vs.val[0], mask2); + vs.val[1] = vceqq_u8(vs.val[1], mask2); + + q2s.val[0] = vmulq_s8(vreinterpretq_s8_u8(vorrq_u8(vs.val[0], m1)), q2s.val[0]); + q2s.val[1] = vmulq_s8(vreinterpretq_s8_u8(vorrq_u8(vs.val[1], m1)), q2s.val[1]); + + vs.val[0] = vreinterpretq_u8_u32(vdupq_n_u32(signs[2] | ((uint32_t) signs[3] << 16))); + vs.val[1] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[1]), mask2); + vs.val[0] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[0]), mask2); + vs.val[0] = vceqq_u8(vs.val[0], mask2); + vs.val[1] = vceqq_u8(vs.val[1], mask2); + + signs += 4; + + q2s.val[2] = vmulq_s8(vreinterpretq_s8_u8(vorrq_u8(vs.val[0], m1)), q2s.val[2]); + q2s.val[3] = vmulq_s8(vreinterpretq_s8_u8(vorrq_u8(vs.val[1], m1)), q2s.val[3]); + + const int32x4_t p1 = ggml_vdotq_s32(vzero, q2s.val[0], q8b.val[0]); + const int32x4_t p2 = ggml_vdotq_s32(vzero, q2s.val[1], q8b.val[1]); + const int32x4_t p3 = ggml_vdotq_s32(vzero, q2s.val[2], q8b.val[2]); + const int32x4_t p4 = ggml_vdotq_s32(vzero, q2s.val[3], q8b.val[3]); + + sumi1 += vaddvq_s32(p1) * (1 + 2*(x[i].scales[ib32+0] & 0xf)); + sumi2 += vaddvq_s32(p2) * (1 + 2*(x[i].scales[ib32+0] >> 4)); + sumi1 += vaddvq_s32(p3) * (1 + 2*(x[i].scales[ib32+1] & 0xf)); + sumi2 += vaddvq_s32(p4) * (1 + 2*(x[i].scales[ib32+1] >> 4)); + } + sumf += d*(sumi1 + sumi2); + } + + *s = 0.125f * sumf; + +#elif defined(__AVX2__) + + static const uint8_t k_mask1[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 + }; + + static const uint8_t k_mask2[32] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + }; + + const __m128i m4 = _mm_set1_epi8(0xf); + const __m128i m1 = _mm_set1_epi8(1); + + const __m256i mask1 = _mm256_loadu_si256((const __m256i*)k_mask1); + const __m256i mask2 = _mm256_loadu_si256((const __m256i*)k_mask2); + + uint64_t aux64; + + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict qs = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const uint16_t * restrict signs = (const uint16_t *)(x[i].qs + QK_K/8); + const int8_t * restrict q8 = y[i].qs; + + memcpy(&aux64, x[i].scales, 8); + const __m128i scales8 = _mm_add_epi8(_mm_slli_epi16(_mm_and_si128(_mm_set_epi64x(aux64 >> 4, aux64), m4), 1), m1); + const __m256i scales16 = _mm256_cvtepi8_epi16(scales8); // 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15 + + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q2_1 = _mm256_set_epi64x(iq2s_grid[qs[3] | ((qh[ib32+0] << 2) & 0x300)], + iq2s_grid[qs[2] | ((qh[ib32+0] << 4) & 0x300)], + iq2s_grid[qs[1] | ((qh[ib32+0] << 6) & 0x300)], + iq2s_grid[qs[0] | ((qh[ib32+0] << 8) & 0x300)]); + const __m256i q2_2 = _mm256_set_epi64x(iq2s_grid[qs[7] | ((qh[ib32+1] << 2) & 0x300)], + iq2s_grid[qs[6] | ((qh[ib32+1] << 4) & 0x300)], + iq2s_grid[qs[5] | ((qh[ib32+1] << 6) & 0x300)], + iq2s_grid[qs[4] | ((qh[ib32+1] << 8) & 0x300)]); + qs += 8; + + __m256i aux256 = _mm256_set1_epi32(signs[0] | ((uint32_t) signs[1] << 16)); + aux256 = _mm256_and_si256(_mm256_shuffle_epi8(aux256,mask1), mask2); + const __m256i s2_1 = _mm256_cmpeq_epi8(aux256, mask2); + const __m256i q8s_1 = _mm256_sub_epi8(_mm256_xor_si256(s2_1, q8_1), s2_1); + + aux256 = _mm256_set1_epi32(signs[2] | ((uint32_t) signs[3] << 16)); + aux256 = _mm256_and_si256(_mm256_shuffle_epi8(aux256,mask1), mask2); + const __m256i s2_2 = _mm256_cmpeq_epi8(aux256, mask2); + const __m256i q8s_2 = _mm256_sub_epi8(_mm256_xor_si256(s2_2, q8_2), s2_2); + + signs += 4; + + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); // blocks 2*ib32+0, 2*ib32+1 + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); // blocks 2*ib32+2, 2*ib32+3 + + const __m256i p1 = _mm256_madd_epi16(dot1, _mm256_shuffle_epi8(scales16, get_scale_shuffle_k4(ib32+0))); + const __m256i p2 = _mm256_madd_epi16(dot2, _mm256_shuffle_epi8(scales16, get_scale_shuffle_k4(ib32+1))); + sumi1 = _mm256_add_epi32(sumi1, p1); + sumi2 = _mm256_add_epi32(sumi2, p2); + } + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accumf); + + } + + *s = 0.125f * hsum_float_8(accumf); + +#else + + float sumf = 0; + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint8_t * signs = qs + QK_K/8; + + int bsum = 0; + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + int ls1 = 1 + 2*(x[i].scales[ib32] & 0xf); + int ls2 = 1 + 2*(x[i].scales[ib32] >> 4); + int sumi1 = 0, sumi2 = 0; + for (int l = 0; l < 2; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2s_grid + (qs[l] | (qh[ib32] << (8-2*l) & 0x300))); + for (int j = 0; j < 8; ++j) { + sumi1 += q8[j] * grid[j] * (signs[l] & kmask_iq2xs[j] ? -1 : 1); + } + q8 += 8; + } + for (int l = 2; l < 4; ++l) { + const uint8_t * grid = (const uint8_t *)(iq2s_grid + (qs[l] | (qh[ib32] << (8-2*l) & 0x300))); + for (int j = 0; j < 8; ++j) { + sumi2 += q8[j] * grid[j] * (signs[l] & kmask_iq2xs[j] ? -1 : 1); + } + q8 += 8; + } + bsum += ls1 * sumi1 + ls2 * sumi2; + qs += 4; + signs += 4; + } + + sumf += d * bsum; + } + + *s = 0.125f * sumf; + +#endif + +} + +void ggml_vec_dot_iq3_xxs_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq3_xxs * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined(__ARM_NEON) + + const uint64_t * signs64 = (const uint64_t *)keven_signs_q2xs; + + uint32_t aux32[2]; + + ggml_int8x16x4_t q3s; + ggml_int8x16x4_t q8b; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict gas = x[i].qs + QK_K/4; + const int8_t * restrict q8 = y[i].qs; + float sumf1 = 0, sumf2 = 0; + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + memcpy(aux32, gas, 2*sizeof(uint32_t)); gas += 2*sizeof(uint32_t); + const uint32x4_t aux32x4_0 = ggml_vld1q_u32(iq3xxs_grid[q3[ 0]], iq3xxs_grid[q3[ 1]], iq3xxs_grid[q3[ 2]], iq3xxs_grid[q3[ 3]]); + const uint32x4_t aux32x4_1 = ggml_vld1q_u32(iq3xxs_grid[q3[ 4]], iq3xxs_grid[q3[ 5]], iq3xxs_grid[q3[ 6]], iq3xxs_grid[q3[ 7]]); + const uint32x4_t aux32x4_2 = ggml_vld1q_u32(iq3xxs_grid[q3[ 8]], iq3xxs_grid[q3[ 9]], iq3xxs_grid[q3[10]], iq3xxs_grid[q3[11]]); + const uint32x4_t aux32x4_3 = ggml_vld1q_u32(iq3xxs_grid[q3[12]], iq3xxs_grid[q3[13]], iq3xxs_grid[q3[14]], iq3xxs_grid[q3[15]]); + q3 += 16; + q3s.val[0] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[0] >> 0) & 127))), vld1_s8((const void *)(signs64 + ((aux32[0] >> 7) & 127)))); + q3s.val[1] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[0] >> 14) & 127))), vld1_s8((const void *)(signs64 + ((aux32[0] >> 21) & 127)))); + q3s.val[2] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[1] >> 0) & 127))), vld1_s8((const void *)(signs64 + ((aux32[1] >> 7) & 127)))); + q3s.val[3] = vcombine_s8(vld1_s8((const void *)(signs64 + ((aux32[1] >> 14) & 127))), vld1_s8((const void *)(signs64 + ((aux32[1] >> 21) & 127)))); + q3s.val[0] = vmulq_s8(q3s.val[0], vreinterpretq_s8_u32(aux32x4_0)); + q3s.val[1] = vmulq_s8(q3s.val[1], vreinterpretq_s8_u32(aux32x4_1)); + q3s.val[2] = vmulq_s8(q3s.val[2], vreinterpretq_s8_u32(aux32x4_2)); + q3s.val[3] = vmulq_s8(q3s.val[3], vreinterpretq_s8_u32(aux32x4_3)); + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q3s.val[0], q8b.val[0]), q3s.val[1], q8b.val[1]); + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q3s.val[2], q8b.val[2]), q3s.val[3], q8b.val[3]); + sumf1 += vaddvq_s32(p1) * (0.5f + (aux32[0] >> 28)); + sumf2 += vaddvq_s32(p2) * (0.5f + (aux32[1] >> 28)); + } + sumf += d*(sumf1 + sumf2); + } + *s = 0.5f * sumf; + +#elif defined(__AVX2__) + + const uint64_t * signs64 = (const uint64_t *)keven_signs_q2xs; + + uint32_t aux32[2]; + + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict gas = x[i].qs + QK_K/4; + const int8_t * restrict q8 = y[i].qs; + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q2_1 = _mm256_set_epi32(iq3xxs_grid[q3[7]], iq3xxs_grid[q3[6]], iq3xxs_grid[q3[5]], iq3xxs_grid[q3[4]], + iq3xxs_grid[q3[3]], iq3xxs_grid[q3[2]], iq3xxs_grid[q3[1]], iq3xxs_grid[q3[0]]); + q3 += 8; + const __m256i q2_2 = _mm256_set_epi32(iq3xxs_grid[q3[7]], iq3xxs_grid[q3[6]], iq3xxs_grid[q3[5]], iq3xxs_grid[q3[4]], + iq3xxs_grid[q3[3]], iq3xxs_grid[q3[2]], iq3xxs_grid[q3[1]], iq3xxs_grid[q3[0]]); + q3 += 8; + memcpy(aux32, gas, 8); gas += 8; + const __m256i s2_1 = _mm256_set_epi64x(signs64[(aux32[0] >> 21) & 127], signs64[(aux32[0] >> 14) & 127], + signs64[(aux32[0] >> 7) & 127], signs64[(aux32[0] >> 0) & 127]); + const __m256i s2_2 = _mm256_set_epi64x(signs64[(aux32[1] >> 21) & 127], signs64[(aux32[1] >> 14) & 127], + signs64[(aux32[1] >> 7) & 127], signs64[(aux32[1] >> 0) & 127]); + const __m256i q8s_1 = _mm256_sign_epi8(q8_1, s2_1); + const __m256i q8s_2 = _mm256_sign_epi8(q8_2, s2_2); + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); + const uint16_t ls1 = aux32[0] >> 28; + const uint16_t ls2 = aux32[1] >> 28; + const __m256i p1 = _mm256_madd_epi16(dot1, _mm256_set1_epi16(2*ls1+1)); + const __m256i p2 = _mm256_madd_epi16(dot2, _mm256_set1_epi16(2*ls2+1)); + sumi1 = _mm256_add_epi32(sumi1, p1); + sumi2 = _mm256_add_epi32(sumi2, p2); + } + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accumf); + + } + + *s = 0.25f * hsum_float_8(accumf); + +#else + + uint32_t aux32; + + float sumf = 0.f; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict gas = x[i].qs + QK_K/4; + const int8_t * restrict q8 = y[i].qs; + int32_t bsum = 0; + for (int ib32 = 0; ib32 < QK_K/32; ++ib32) { + memcpy(&aux32, gas, sizeof(uint32_t)); gas += sizeof(uint32_t); + const uint32_t ls = 2*(aux32 >> 28) + 1; + int32_t sumi = 0; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid1 = (const uint8_t *)(iq3xxs_grid + q3[2*l+0]); + const uint8_t * grid2 = (const uint8_t *)(iq3xxs_grid + q3[2*l+1]); + const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*l) & 127]; + for (int j = 0; j < 4; ++j) { + sumi += grid1[j] * q8[j+0] * (signs & kmask_iq2xs[j+0] ? -1 : 1); + sumi += grid2[j] * q8[j+4] * (signs & kmask_iq2xs[j+4] ? -1 : 1); + } + q8 += 8; + } + q3 += 8; + bsum += sumi * ls; + } + sumf += d * bsum; + } + *s = 0.25f * sumf; +#endif +} + +void ggml_vec_dot_iq3_s_q8_K (int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq3_s * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined(__ARM_NEON) + + typedef union { + uint16x8_t vec_index; + uint16_t index[8]; + } vec_index_t; + + static const uint8_t k_mask1[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 + }; + + static const uint8_t k_mask2[16] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,}; + + static const int16_t k_shift[8] = {8, 7, 6, 5, 4, 3, 2, 1}; + + const ggml_uint8x16x2_t mask1 = ggml_vld1q_u8_x2(k_mask1); + const uint8x16_t mask2 = vld1q_u8(k_mask2); + + const int16x8_t hshift = vld1q_s16(k_shift); + const uint16x8_t m256 = vdupq_n_u16(256); + const uint8x16_t m1 = vdupq_n_u8(1); + + uint8x16x2_t vs; + ggml_int8x16x4_t q3s; + ggml_int8x16x4_t q8b; + vec_index_t idx; + +#if QK_K == 256 + uint32_t scales32[2]; + const uint8_t * scales8 = (const uint8_t *)scales32; +#endif + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict qs = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const uint16_t * restrict signs = (const uint16_t *)x[i].signs; + const int8_t * restrict q8 = y[i].qs; + +#if QK_K == 256 + memcpy(scales32, x[i].scales, 4); + scales32[1] = (((scales32[0] >> 4) & 0x0f0f0f0f) << 1) | 0x01010101; + scales32[0] = ((scales32[0] & 0x0f0f0f0f) << 1) | 0x01010101; +#endif + + int sumi1 = 0, sumi2 = 0; + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + + const uint8x16_t idx_l = vld1q_u8(qs); qs += 16; + idx.vec_index = vorrq_u16(vmovl_u8(vget_low_u8 (idx_l)), vandq_u16(vshlq_u16(vdupq_n_u16(qh[ib32+0]), hshift), m256)); + const uint32x4_t aux32x4_0 = ggml_vld1q_u32(iq3s_grid[idx.index[0]], iq3s_grid[idx.index[1]], + iq3s_grid[idx.index[2]], iq3s_grid[idx.index[3]]); + const uint32x4_t aux32x4_1 = ggml_vld1q_u32(iq3s_grid[idx.index[4]], iq3s_grid[idx.index[5]], + iq3s_grid[idx.index[6]], iq3s_grid[idx.index[7]]); + idx.vec_index = vorrq_u16(vmovl_u8(vget_high_u8(idx_l)), vandq_u16(vshlq_u16(vdupq_n_u16(qh[ib32+1]), hshift), m256)); + const uint32x4_t aux32x4_2 = ggml_vld1q_u32(iq3s_grid[idx.index[0]], iq3s_grid[idx.index[1]], + iq3s_grid[idx.index[2]], iq3s_grid[idx.index[3]]); + const uint32x4_t aux32x4_3 = ggml_vld1q_u32(iq3s_grid[idx.index[4]], iq3s_grid[idx.index[5]], + iq3s_grid[idx.index[6]], iq3s_grid[idx.index[7]]); + + + vs.val[0] = vreinterpretq_u8_u32(vdupq_n_u32(signs[0] | ((uint32_t) signs[1] << 16))); + vs.val[1] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[1]), mask2); + vs.val[0] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[0]), mask2); + vs.val[0] = vorrq_u8(vceqq_u8(vs.val[0], mask2), m1); + vs.val[1] = vorrq_u8(vceqq_u8(vs.val[1], mask2), m1); + + q3s.val[0] = vmulq_s8(vreinterpretq_s8_u8(vs.val[0]), vreinterpretq_s8_u32(aux32x4_0)); + q3s.val[1] = vmulq_s8(vreinterpretq_s8_u8(vs.val[1]), vreinterpretq_s8_u32(aux32x4_1)); + + vs.val[0] = vreinterpretq_u8_u32(vdupq_n_u32(signs[2] | ((uint32_t) signs[3] << 16))); + vs.val[1] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[1]), mask2); + vs.val[0] = vandq_u8(ggml_vqtbl1q_u8(vs.val[0], mask1.val[0]), mask2); + vs.val[0] = vorrq_u8(vceqq_u8(vs.val[0], mask2), m1); + vs.val[1] = vorrq_u8(vceqq_u8(vs.val[1], mask2), m1); + + signs += 4; + + q3s.val[2] = vmulq_s8(vreinterpretq_s8_u8(vs.val[0]), vreinterpretq_s8_u32(aux32x4_2)); + q3s.val[3] = vmulq_s8(vreinterpretq_s8_u8(vs.val[1]), vreinterpretq_s8_u32(aux32x4_3)); + + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q3s.val[0], q8b.val[0]), q3s.val[1], q8b.val[1]); + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q3s.val[2], q8b.val[2]), q3s.val[3], q8b.val[3]); +#if QK_K == 256 + sumi1 += vaddvq_s32(p1) * scales8[ib32/2+0]; + sumi2 += vaddvq_s32(p2) * scales8[ib32/2+4]; +#else + sumi1 += vaddvq_s32(p1) * (1 + 2*(x[i].scales[ib32/2] & 0xf)); + sumi2 += vaddvq_s32(p2) * (1 + 2*(x[i].scales[ib32/2] >> 4)); +#endif + } + sumf += d*(sumi1 + sumi2); + } + *s = sumf; + +#elif defined(__AVX2__) + + static const uint8_t k_mask1[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 + }; + + static const uint8_t k_mask2[32] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + }; + + const __m256i mask1 = _mm256_loadu_si256((const __m256i*)k_mask1); + const __m256i mask2 = _mm256_loadu_si256((const __m256i*)k_mask2); + + const __m256i idx_shift = _mm256_set_epi32(1, 2, 3, 4, 5, 6, 7, 8); + const __m256i idx_mask = _mm256_set1_epi32(256); + + typedef union { + __m256i vec[2]; + uint32_t index[16]; + } index_t; + + index_t idx; + + __m256 accumf = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict qs = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const uint16_t * restrict signs = (const uint16_t *)x[i].signs; + const int8_t * restrict q8 = y[i].qs; + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const __m256i q8_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i idx_l = _mm256_cvtepu8_epi16(_mm_loadu_si128((const __m128i *)qs)); qs += 16; + idx.vec[0] = _mm256_set1_epi32(qh[ib32+0]); + idx.vec[1] = _mm256_set1_epi32(qh[ib32+1]); + idx.vec[0] = _mm256_and_si256(_mm256_sllv_epi32(idx.vec[0], idx_shift), idx_mask); + idx.vec[1] = _mm256_and_si256(_mm256_sllv_epi32(idx.vec[1], idx_shift), idx_mask); + idx.vec[0] = _mm256_or_si256(idx.vec[0], _mm256_cvtepi16_epi32(_mm256_castsi256_si128(idx_l))); + idx.vec[1] = _mm256_or_si256(idx.vec[1], _mm256_cvtepi16_epi32(_mm256_extractf128_si256(idx_l, 1))); + + // At leat on my CPU (Ryzen 7950X), using _mm256_i32gather_epi32 is slower than _mm256_set_epi32. Strange. + //const __m256i q2_1 = _mm256_i32gather_epi32((const int *)iq3s_grid, idx.vec[0], 4); + //const __m256i q2_2 = _mm256_i32gather_epi32((const int *)iq3s_grid, idx.vec[1], 4); + const __m256i q2_1 = _mm256_set_epi32( + iq3s_grid[idx.index[7]], iq3s_grid[idx.index[6]], iq3s_grid[idx.index[5]], iq3s_grid[idx.index[4]], + iq3s_grid[idx.index[3]], iq3s_grid[idx.index[2]], iq3s_grid[idx.index[1]], iq3s_grid[idx.index[0]] + ); + const __m256i q2_2 = _mm256_set_epi32( + iq3s_grid[idx.index[15]], iq3s_grid[idx.index[14]], iq3s_grid[idx.index[13]], iq3s_grid[idx.index[12]], + iq3s_grid[idx.index[11]], iq3s_grid[idx.index[10]], iq3s_grid[idx.index[ 9]], iq3s_grid[idx.index[ 8]] + ); + + __m256i aux256 = _mm256_set1_epi32(signs[0] | (signs[1] << 16)); + aux256 = _mm256_and_si256(_mm256_shuffle_epi8(aux256,mask1), mask2); + const __m256i s2_1 = _mm256_cmpeq_epi8(aux256, mask2); + const __m256i q8s_1 = _mm256_sub_epi8(_mm256_xor_si256(s2_1, q8_1), s2_1); + + aux256 = _mm256_set1_epi32(signs[2] | (signs[3] << 16)); + aux256 = _mm256_and_si256(_mm256_shuffle_epi8(aux256,mask1), mask2); + const __m256i s2_2 = _mm256_cmpeq_epi8(aux256, mask2); + const __m256i q8s_2 = _mm256_sub_epi8(_mm256_xor_si256(s2_2, q8_2), s2_2); + + signs += 4; + + const __m256i dot1 = _mm256_maddubs_epi16(q2_1, q8s_1); + const __m256i dot2 = _mm256_maddubs_epi16(q2_2, q8s_2); + const uint16_t ls1 = x[i].scales[ib32/2] & 0xf; + const uint16_t ls2 = x[i].scales[ib32/2] >> 4; + const __m256i p1 = _mm256_madd_epi16(dot1, _mm256_set1_epi16(2*ls1+1)); + const __m256i p2 = _mm256_madd_epi16(dot2, _mm256_set1_epi16(2*ls2+1)); + sumi1 = _mm256_add_epi32(sumi1, p1); + sumi2 = _mm256_add_epi32(sumi2, p2); + } + + accumf = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accumf); + + } + + *s = hsum_float_8(accumf); + +#else + + float sumf = 0.f; + for (int i = 0; i < nb; ++i) { + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const uint8_t * restrict qs = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const uint8_t * restrict signs = x[i].signs; + const int8_t * restrict q8 = y[i].qs; + int32_t bsum = 0; + for (int ib32 = 0; ib32 < QK_K/32; ib32 += 2) { + const uint32_t ls1 = 2*(x[i].scales[ib32/2] & 0xf) + 1; + const uint32_t ls2 = 2*(x[i].scales[ib32/2] >> 4) + 1; + int32_t sumi = 0; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*l+0] | ((qh[ib32+0] << (8-2*l)) & 256))); + const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*l+1] | ((qh[ib32+0] << (7-2*l)) & 256))); + for (int j = 0; j < 4; ++j) { + sumi += grid1[j] * q8[j+0] * (signs[l] & kmask_iq2xs[j+0] ? -1 : 1); + sumi += grid2[j] * q8[j+4] * (signs[l] & kmask_iq2xs[j+4] ? -1 : 1); + } + q8 += 8; + } + qs += 8; + signs += 4; + bsum += sumi * ls1; + sumi = 0; + for (int l = 0; l < 4; ++l) { + const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*l+0] | ((qh[ib32+1] << (8-2*l)) & 256))); + const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*l+1] | ((qh[ib32+1] << (7-2*l)) & 256))); + for (int j = 0; j < 4; ++j) { + sumi += grid1[j] * q8[j+0] * (signs[l] & kmask_iq2xs[j+0] ? -1 : 1); + sumi += grid2[j] * q8[j+4] * (signs[l] & kmask_iq2xs[j+4] ? -1 : 1); + } + q8 += 8; + } + qs += 8; + signs += 4; + bsum += sumi * ls2; + } + sumf += d * bsum; + } + *s = sumf; +#endif +} + + +#ifdef __AVX2__ +static inline __m256i mul_add_epi8(const __m256i x, const __m256i y) { + const __m256i ax = _mm256_sign_epi8(x, x); + const __m256i sy = _mm256_sign_epi8(y, x); + return _mm256_maddubs_epi16(ax, sy); +} +#endif + +void ggml_vec_dot_iq1_s_q8_K (int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq1_s * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined __ARM_NEON + + ggml_int8x16x4_t q1b; + ggml_int8x16x4_t q8b; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint16_t * qh = x[i].qh; + + int sumi1 = 0, sumi2 = 0, sumi3 = 0; + + for (int ib = 0; ib < QK_K/32; ib += 2) { + + q1b.val[0] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[0] | ((qh[ib+0] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[1] | ((qh[ib+0] << 5) & 0x700))))); + q1b.val[1] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[2] | ((qh[ib+0] << 2) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[3] | ((qh[ib+0] >> 1) & 0x700))))); + q1b.val[2] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[4] | ((qh[ib+1] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[5] | ((qh[ib+1] << 5) & 0x700))))); + q1b.val[3] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[6] | ((qh[ib+1] << 2) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[7] | ((qh[ib+1] >> 1) & 0x700))))); + qs += 8; + + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + + const int32x4_t p1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q1b.val[0], q8b.val[0]), q1b.val[1], q8b.val[1]); + const int32x4_t p2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q1b.val[2], q8b.val[2]), q1b.val[3], q8b.val[3]); + + const int ls1 = 2*((qh[ib+0] >> 12) & 7) + 1; + const int ls2 = 2*((qh[ib+1] >> 12) & 7) + 1; + sumi1 += vaddvq_s32(p1) * ls1; + sumi2 += vaddvq_s32(p2) * ls2; + sumi3 += (y[i].bsums[2*ib+0] + y[i].bsums[2*ib+1]) * ls1 * (qh[ib+0] & 0x8000 ? -1 : 1) + + (y[i].bsums[2*ib+2] + y[i].bsums[2*ib+3]) * ls2 * (qh[ib+1] & 0x8000 ? -1 : 1); + + } + + sumf += y[i].d * GGML_FP16_TO_FP32(x[i].d) * (sumi1 + sumi2 + IQ1S_DELTA * sumi3); + } + + *s = sumf; + +#elif defined __AVX2__ + + __m256 accum = _mm256_setzero_ps(); + float accum1 = 0; + for (int i = 0; i < nb; ++i) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint16_t * qh = x[i].qh; + + __m256i sumi = _mm256_setzero_si256(); + int sumi1 = 0; + for (int ib = 0; ib < QK_K/32; ib += 2) { + const __m256i q1b_1 = _mm256_set_epi64x(iq1s_grid[qs[3] | ((qh[ib+0] >> 1) & 0x700)], iq1s_grid[qs[2] | ((qh[ib+0] << 2) & 0x700)], + iq1s_grid[qs[1] | ((qh[ib+0] << 5) & 0x700)], iq1s_grid[qs[0] | ((qh[ib+0] << 8) & 0x700)]); + const __m256i q1b_2 = _mm256_set_epi64x(iq1s_grid[qs[7] | ((qh[ib+1] >> 1) & 0x700)], iq1s_grid[qs[6] | ((qh[ib+1] << 2) & 0x700)], + iq1s_grid[qs[5] | ((qh[ib+1] << 5) & 0x700)], iq1s_grid[qs[4] | ((qh[ib+1] << 8) & 0x700)]); + qs += 8; + const __m256i q8b_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8b_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + const __m256i dot1 = mul_add_epi8(q1b_1, q8b_1); + const __m256i dot2 = mul_add_epi8(q1b_2, q8b_2); + const int16_t ls1 = 2*((qh[ib+0] >> 12) & 7) + 1; + const int16_t ls2 = 2*((qh[ib+1] >> 12) & 7) + 1; + const __m256i p1 = _mm256_madd_epi16(dot1, _mm256_set1_epi16(ls1)); + const __m256i p2 = _mm256_madd_epi16(dot2, _mm256_set1_epi16(ls2)); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p1, p2)); + sumi1 += (y[i].bsums[2*ib+0] + y[i].bsums[2*ib+1]) * (qh[ib+0] & 0x8000 ? -1 : 1) * ls1 + + (y[i].bsums[2*ib+2] + y[i].bsums[2*ib+3]) * (qh[ib+1] & 0x8000 ? -1 : 1) * ls2; + } + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + accum = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(sumi), accum); + accum1 += d * sumi1; + + } + + *s = hsum_float_8(accum) + IQ1S_DELTA * accum1; + +#else + + float sumf = 0; + for (int i = 0; i < nb; i++) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint16_t * qh = x[i].qh; + + int sumi = 0, sumi1 = 0; + for (int ib = 0; ib < QK_K/32; ++ib) { + const int ls = 2*((qh[ib] >> 12) & 7) + 1; + const int delta = qh[ib] & 0x8000 ? -1 : 1; + int lsum = 0; + for (int l = 0; l < 4; ++l) { + const int8_t * grid = (const int8_t *)(iq1s_grid + (qs[l] | (((qh[ib] >> 3*l) & 7) << 8))); + for (int j = 0; j < 8; ++j) { + lsum += q8[j] * grid[j]; + } + q8 += 8; + } + sumi += ls * lsum; + sumi1 += ls * delta * (y[i].bsums[2*ib+0] + y[i].bsums[2*ib+1]); + qs += 4; + } + + sumf += GGML_FP16_TO_FP32(x[i].d) * y[i].d * (sumi + IQ1S_DELTA * sumi1); + } + + *s = sumf; + +#endif +} + +void ggml_vec_dot_iq1_m_q8_K (int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(n % QK_K == 0); + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + + const block_iq1_m * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if QK_K != 64 + iq1m_scale_t scale; +#endif + +#if defined __ARM_NEON + +#if QK_K == 64 + const int32x4_t mask = vdupq_n_s32(0xf); +#else + const int32x4_t mask = vdupq_n_s32(0x7); +#endif + const int32x4_t mone = vdupq_n_s32(1); + const int32x4_t mzero = vdupq_n_s32(0); + + ggml_int8x16x4_t deltas; + deltas.val[0] = vcombine_s8(vdup_n_s8(+1), vdup_n_s8(+1)); + deltas.val[1] = vcombine_s8(vdup_n_s8(-1), vdup_n_s8(+1)); + deltas.val[2] = vcombine_s8(vdup_n_s8(+1), vdup_n_s8(-1)); + deltas.val[3] = vcombine_s8(vdup_n_s8(-1), vdup_n_s8(-1)); + + ggml_int8x16x4_t q1b; + ggml_int8x16x4_t q8b; + + uint32_t aux32; + const uint8_t * aux8 = (const uint8_t *)&aux32; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint16_t * sc = (const uint16_t *)x[i].scales; + +#if QK_K != 64 + scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000); +#endif + + int32x4_t sumi1 = mzero; + int32x4_t sumi2 = mzero; + + for (int ib = 0; ib < QK_K/32; ib += 2) { + + q1b.val[0] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[0] | ((qh[0] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[1] | ((qh[0] << 4) & 0x700))))); + q1b.val[1] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[2] | ((qh[1] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[3] | ((qh[1] << 4) & 0x700))))); + q1b.val[2] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[4] | ((qh[2] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[5] | ((qh[2] << 4) & 0x700))))); + q1b.val[3] = vcombine_s8(vld1_s8((const int8_t *)(iq1s_grid + (qs[6] | ((qh[3] << 8) & 0x700)))), + vld1_s8((const int8_t *)(iq1s_grid + (qs[7] | ((qh[3] << 4) & 0x700))))); + + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + + const int32x4_t p1 = vpaddq_s32(ggml_vdotq_s32(mzero, q1b.val[0], q8b.val[0]), ggml_vdotq_s32(mzero, q1b.val[1], q8b.val[1])); + const int32x4_t p2 = vpaddq_s32(ggml_vdotq_s32(mzero, q1b.val[2], q8b.val[2]), ggml_vdotq_s32(mzero, q1b.val[3], q8b.val[3])); + const int32x4_t p12 = vpaddq_s32(p1, p2); + + const uint32_t * qh32 = (const uint32_t *)qh; // we are 4-byte aligned, so we can do that + aux32 = ((qh32[0] >> 3) & 0x01010101) | ((qh32[0] >> 6) & 0x02020202); + + const int32x4_t p3 = vpaddq_s32(ggml_vdotq_s32(mzero, deltas.val[aux8[0]], q8b.val[0]), ggml_vdotq_s32(mzero, deltas.val[aux8[1]], q8b.val[1])); + const int32x4_t p4 = vpaddq_s32(ggml_vdotq_s32(mzero, deltas.val[aux8[2]], q8b.val[2]), ggml_vdotq_s32(mzero, deltas.val[aux8[3]], q8b.val[3])); + const int32x4_t p34 = vpaddq_s32(p3, p4); + +#if QK_K == 64 + int32x4_t scales_4 = ggml_vld1q_u32(sc[0] >> 0, sc[0] >> 4, sc[0] >> 8, sc[0] >> 12); +#else + int32x4_t scales_4 = ggml_vld1q_u32(sc[ib/2] >> 0, sc[ib/2] >> 3, sc[ib/2] >> 6, sc[ib/2] >> 9); +#endif + scales_4 = vaddq_s32(vshlq_n_s32(vandq_s32(scales_4, mask), 1), mone); + + sumi1 = vmlaq_s32(sumi1, scales_4, p12); + sumi2 = vmlaq_s32(sumi2, scales_4, p34); + + qs += 8; qh += 4; + + } + +#if QK_K == 64 + sumf += y[i].d * GGML_FP16_TO_FP32(x[i].d) * (vaddvq_s32(sumi1) + IQ1M_DELTA * vaddvq_s32(sumi2)); +#else + sumf += y[i].d * GGML_FP16_TO_FP32(scale.f16) * (vaddvq_s32(sumi1) + IQ1M_DELTA * vaddvq_s32(sumi2)); +#endif + } + + *s = sumf; + +#elif defined __AVX2__ + +#if QK_K == 64 + const __m256i mask = _mm256_set1_epi16(0xf); +#else + const __m256i mask = _mm256_set1_epi16(0x7); +#endif + const __m256i mone = _mm256_set1_epi16(1); + + __m256 accum1 = _mm256_setzero_ps(); + __m256 accum2 = _mm256_setzero_ps(); + for (int i = 0; i < nb; ++i) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint16_t * sc = (const uint16_t *)x[i].scales; + +#if QK_K != 64 + scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000); +#endif + + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib = 0; ib < QK_K/32; ib += 2) { + const __m256i q1b_1 = _mm256_set_epi64x( + iq1s_grid[qs[3] | (((uint16_t)qh[1] << 4) & 0x700)], iq1s_grid[qs[2] | (((uint16_t)qh[1] << 8) & 0x700)], + iq1s_grid[qs[1] | (((uint16_t)qh[0] << 4) & 0x700)], iq1s_grid[qs[0] | (((uint16_t)qh[0] << 8) & 0x700)] + ); + const __m256i q1b_2 = _mm256_set_epi64x( + iq1s_grid[qs[7] | (((uint16_t)qh[3] << 4) & 0x700)], iq1s_grid[qs[6] | (((uint16_t)qh[3] << 8) & 0x700)], + iq1s_grid[qs[5] | (((uint16_t)qh[2] << 4) & 0x700)], iq1s_grid[qs[4] | (((uint16_t)qh[2] << 8) & 0x700)] + ); + const __m256i q8b_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8b_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + const __m256i dot1 = mul_add_epi8(q1b_1, q8b_1); + const __m256i dot2 = mul_add_epi8(q1b_2, q8b_2); + + const __m256i delta1 = _mm256_set_epi64x(qh[1] & 0x80 ? 0xffffffffffffffff : 0x0101010101010101, + qh[1] & 0x08 ? 0xffffffffffffffff : 0x0101010101010101, + qh[0] & 0x80 ? 0xffffffffffffffff : 0x0101010101010101, + qh[0] & 0x08 ? 0xffffffffffffffff : 0x0101010101010101); + const __m256i delta2 = _mm256_set_epi64x(qh[3] & 0x80 ? 0xffffffffffffffff : 0x0101010101010101, + qh[3] & 0x08 ? 0xffffffffffffffff : 0x0101010101010101, + qh[2] & 0x80 ? 0xffffffffffffffff : 0x0101010101010101, + qh[2] & 0x08 ? 0xffffffffffffffff : 0x0101010101010101); + + const __m256i dot3 = mul_add_epi8(delta1, q8b_1); + const __m256i dot4 = mul_add_epi8(delta2, q8b_2); +#if QK_K == 64 + __m256i scale1 = MM256_SET_M128I(_mm_set1_epi16(sc[0] >> 4), _mm_set1_epi16(sc[0] >> 0)); + __m256i scale2 = MM256_SET_M128I(_mm_set1_epi16(sc[0] >> 12), _mm_set1_epi16(sc[0] >> 8)); +#else + __m256i scale1 = MM256_SET_M128I(_mm_set1_epi16(sc[ib/2] >> 3), _mm_set1_epi16(sc[ib/2] >> 0)); + __m256i scale2 = MM256_SET_M128I(_mm_set1_epi16(sc[ib/2] >> 9), _mm_set1_epi16(sc[ib/2] >> 6)); +#endif + scale1 = _mm256_add_epi16(_mm256_slli_epi16(_mm256_and_si256(scale1, mask), 1), mone); + scale2 = _mm256_add_epi16(_mm256_slli_epi16(_mm256_and_si256(scale2, mask), 1), mone); + const __m256i p1 = _mm256_madd_epi16(dot1, scale1); + const __m256i p2 = _mm256_madd_epi16(dot2, scale2); + const __m256i p3 = _mm256_madd_epi16(dot3, scale1); + const __m256i p4 = _mm256_madd_epi16(dot4, scale2); + + sumi1 = _mm256_add_epi32(sumi1, _mm256_add_epi32(p1, p2)); + sumi2 = _mm256_add_epi32(sumi2, _mm256_add_epi32(p3, p4)); + + qs += 8; qh += 4; + } + +#if QK_K == 64 + const __m256 d = _mm256_set1_ps(y[i].d * GGML_FP16_TO_FP32(x[i].d)); +#else + const __m256 d = _mm256_set1_ps(y[i].d * GGML_FP16_TO_FP32(scale.f16)); +#endif + accum1 = _mm256_fmadd_ps(d, _mm256_cvtepi32_ps(sumi1), accum1); + accum2 = _mm256_fmadd_ps(d, _mm256_cvtepi32_ps(sumi2), accum2); + + } + + *s = hsum_float_8(accum1) + IQ1M_DELTA * hsum_float_8(accum2); + +#else + + int sum1[2], sum2[2], delta[4]; + + float sumf = 0; + for (int i = 0; i < nb; i++) { + + const int8_t * q8 = y[i].qs; + const uint8_t * qs = x[i].qs; + const uint8_t * qh = x[i].qh; + const uint16_t * sc = (const uint16_t *)x[i].scales; + +#if QK_K != 64 + scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000); +#endif + + int sumi1 = 0, sumi2 = 0; + for (int ib = 0; ib < QK_K/32; ++ib) { + delta[0] = qh[0] & 0x08 ? -1 : 1; + delta[1] = qh[0] & 0x80 ? -1 : 1; + delta[2] = qh[1] & 0x08 ? -1 : 1; + delta[3] = qh[1] & 0x80 ? -1 : 1; + sum1[0] = sum1[1] = sum2[0] = sum2[1] = 0; + for (int l = 0; l < 4; ++l) { + const int8_t * grid = (const int8_t *)(iq1s_grid + (qs[l] | (((uint16_t)qh[l/2] << (8 - 4*(l%2))) & 0x700))); + int lsum1 = 0, lsum2 = 0; + for (int j = 0; j < 8; ++j) { + lsum1 += q8[j] * grid[j]; + lsum2 += q8[j]; + } + q8 += 8; + sum1[l/2] += lsum1; + sum2[l/2] += lsum2*delta[l]; + } +#if QK_K == 64 + const int ls1 = 2*((sc[0] >> (8*(ib%2)+0)) & 0xf) + 1; + const int ls2 = 2*((sc[0] >> (8*(ib%2)+4)) & 0xf) + 1; +#else + const int ls1 = 2*((sc[ib/2] >> (6*(ib%2)+0)) & 0x7) + 1; + const int ls2 = 2*((sc[ib/2] >> (6*(ib%2)+3)) & 0x7) + 1; +#endif + sumi1 += sum1[0] * ls1 + sum1[1] * ls2; + sumi2 += sum2[0] * ls1 + sum2[1] * ls2; + qs += 4; + qh += 2; + } + +#if QK_K == 64 + sumf += GGML_FP16_TO_FP32(x[i].d) * y[i].d * (sumi1 + IQ1M_DELTA * sumi2); +#else + sumf += GGML_FP16_TO_FP32(scale.f16) * y[i].d * (sumi1 + IQ1M_DELTA * sumi2); +#endif + } + + *s = sumf; + +#endif +} + +void ggml_vec_dot_iq4_nl_q8_0(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + assert(n % QK4_NL == 0); + static_assert(QK4_NL == QK8_0, "QK4_NL and QK8_0 must be the same"); + + const block_iq4_nl * restrict x = vx; + const block_q8_0 * restrict y = vy; + + const int nb = n / QK4_NL; + +#if defined __ARM_NEON + const int8x16_t values = vld1q_s8(kvalues_iq4nl); + const uint8x16_t m4b = vdupq_n_u8(0x0f); + uint8x16x2_t q4bits; + int8x16x4_t q4b; + int8x16x4_t q8b; + int32x4_t prod_1, prod_2; + + float sumf = 0; + + for (int ib = 0; ib < nb; ib += 2) { + + q4bits.val[0] = vld1q_u8(x[ib+0].qs); + q4bits.val[1] = vld1q_u8(x[ib+1].qs); + q8b.val[0] = vld1q_s8(y[ib+0].qs); + q8b.val[1] = vld1q_s8(y[ib+0].qs + 16); + q8b.val[2] = vld1q_s8(y[ib+1].qs); + q8b.val[3] = vld1q_s8(y[ib+1].qs + 16); + + q4b.val[0] = ggml_vqtbl1q_s8(values, vandq_u8 (q4bits.val[0], m4b)); + q4b.val[1] = ggml_vqtbl1q_s8(values, vshrq_n_u8(q4bits.val[0], 4)); + q4b.val[2] = ggml_vqtbl1q_s8(values, vandq_u8 (q4bits.val[1], m4b)); + q4b.val[3] = ggml_vqtbl1q_s8(values, vshrq_n_u8(q4bits.val[1], 4)); + + prod_1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q4b.val[0], q8b.val[0]), q4b.val[1], q8b.val[1]); + prod_2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q4b.val[2], q8b.val[2]), q4b.val[3], q8b.val[3]); + + sumf += + GGML_FP16_TO_FP32(x[ib+0].d) * GGML_FP16_TO_FP32(y[ib+0].d) * vaddvq_s32(prod_1) + + GGML_FP16_TO_FP32(x[ib+1].d) * GGML_FP16_TO_FP32(y[ib+1].d) * vaddvq_s32(prod_2); + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m128i values128 = _mm_loadu_si128((const __m128i*)kvalues_iq4nl); + const __m128i m4b = _mm_set1_epi8(0x0f); + const __m256i mone = _mm256_set1_epi16(1); + + __m256 accum1 = _mm256_setzero_ps(); + __m256 accum2 = _mm256_setzero_ps(); + for (int ib = 0; ib < nb; ib += 2) { + const __m128i q4bits_1 = _mm_loadu_si128((const __m128i*)x[0].qs); + const __m128i q4bits_2 = _mm_loadu_si128((const __m128i*)x[1].qs); + const __m256i q8b_1 = _mm256_loadu_si256((const __m256i *)y[0].qs); + const __m256i q8b_2 = _mm256_loadu_si256((const __m256i *)y[1].qs); + const __m256i q4b_1 = MM256_SET_M128I(_mm_shuffle_epi8(values128, _mm_and_si128(_mm_srli_epi16(q4bits_1, 4), m4b)), + _mm_shuffle_epi8(values128, _mm_and_si128(q4bits_1, m4b))); + const __m256i q4b_2 = MM256_SET_M128I(_mm_shuffle_epi8(values128, _mm_and_si128(_mm_srli_epi16(q4bits_2, 4), m4b)), + _mm_shuffle_epi8(values128, _mm_and_si128(q4bits_2, m4b))); + const __m256i p16_1 = mul_add_epi8(q4b_1, q8b_1); + const __m256i p16_2 = mul_add_epi8(q4b_2, q8b_2); + const __m256i p_1 = _mm256_madd_epi16(p16_1, mone); + const __m256i p_2 = _mm256_madd_epi16(p16_2, mone); + accum1 = _mm256_fmadd_ps(_mm256_set1_ps(GGML_FP16_TO_FP32(y[0].d)*GGML_FP16_TO_FP32(x[0].d)), + _mm256_cvtepi32_ps(p_1), accum1); + accum2 = _mm256_fmadd_ps(_mm256_set1_ps(GGML_FP16_TO_FP32(y[1].d)*GGML_FP16_TO_FP32(x[1].d)), + _mm256_cvtepi32_ps(p_2), accum2); + + y += 2; + x += 2; + } + + *s = hsum_float_8(_mm256_add_ps(accum1, accum2)); + +#else + float sumf = 0; + for (int ib = 0; ib < nb; ++ib) { + const float d = GGML_FP16_TO_FP32(y[ib].d)*GGML_FP16_TO_FP32(x[ib].d); + int sumi1 = 0, sumi2 = 0; + for (int j = 0; j < QK4_NL/2; ++j) { + sumi1 += y[ib].qs[j+ 0] * kvalues_iq4nl[x[ib].qs[j] & 0xf]; + sumi2 += y[ib].qs[j+QK4_NL/2] * kvalues_iq4nl[x[ib].qs[j] >> 4]; + } + sumf += d * (sumi1 + sumi2); + } + *s = sumf; +#endif +} + +void ggml_vec_dot_iq4_xs_q8_K(int n, float * restrict s, size_t bs, const void * restrict vx, size_t bx, const void * restrict vy, size_t by, int nrc) { + assert(nrc == 1); + UNUSED(nrc); + UNUSED(bx); + UNUSED(by); + UNUSED(bs); + assert(n % QK_K == 0); +#if QK_K == 64 + ggml_vec_dot_iq4_nl_q8_0(n, s, bs, vx, bx, vy, by, nrc); +#else + + const block_iq4_xs * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#if defined __ARM_NEON + const int8x16_t values = vld1q_s8(kvalues_iq4nl); + const uint8x16_t m4b = vdupq_n_u8(0x0f); + ggml_uint8x16x2_t q4bits; + ggml_int8x16x4_t q4b; + ggml_int8x16x4_t q8b; + int32x4_t prod_1, prod_2; + + float sumf = 0; + + for (int ibl = 0; ibl < nb; ++ibl) { + + const int8_t * q8 = y[ibl].qs; + const uint8_t * q4 = x[ibl].qs; + uint16_t h = x[ibl].scales_h; + + int sumi1 = 0, sumi2 = 0; + for (int ib = 0; ib < QK_K/64; ++ib) { + + q4bits = ggml_vld1q_u8_x2(q4); q4 += 32; + q8b = ggml_vld1q_s8_x4(q8); q8 += 64; + + q4b.val[0] = ggml_vqtbl1q_s8(values, vandq_u8 (q4bits.val[0], m4b)); + q4b.val[1] = ggml_vqtbl1q_s8(values, vshrq_n_u8(q4bits.val[0], 4)); + q4b.val[2] = ggml_vqtbl1q_s8(values, vandq_u8 (q4bits.val[1], m4b)); + q4b.val[3] = ggml_vqtbl1q_s8(values, vshrq_n_u8(q4bits.val[1], 4)); + + prod_1 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q4b.val[0], q8b.val[0]), q4b.val[1], q8b.val[1]); + prod_2 = ggml_vdotq_s32(ggml_vdotq_s32(vdupq_n_s32(0), q4b.val[2], q8b.val[2]), q4b.val[3], q8b.val[3]); + + int ls1 = ((x[ibl].scales_l[ib] & 0xf) | ((h << 4) & 0x30)) - 32; + int ls2 = ((x[ibl].scales_l[ib] >> 4) | ((h << 2) & 0x30)) - 32; + h >>= 4; + sumi1 += vaddvq_s32(prod_1) * ls1; + sumi2 += vaddvq_s32(prod_2) * ls2; + + } + + sumf += GGML_FP16_TO_FP32(x[ibl].d) * y[ibl].d * (sumi1 + sumi2); + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m128i values128 = _mm_loadu_si128((const __m128i*)kvalues_iq4nl); + const __m128i m4b = _mm_set1_epi8(0x0f); + + __m256 accum = _mm256_setzero_ps(); + for (int ibl = 0; ibl < nb; ++ibl) { + const uint8_t * qs = x[ibl].qs; + const int8_t * q8 = y[ibl].qs; + uint16_t sh = x[ibl].scales_h; + __m256i sumi1 = _mm256_setzero_si256(); + __m256i sumi2 = _mm256_setzero_si256(); + for (int ib = 0; ib < QK_K/32; ib += 2) { + const __m128i q4bits_1 = _mm_loadu_si128((const __m128i*)qs); qs += 16; + const __m128i q4bits_2 = _mm_loadu_si128((const __m128i*)qs); qs += 16; + const __m256i q8b_1 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q8b_2 = _mm256_loadu_si256((const __m256i *)q8); q8 += 32; + const __m256i q4b_1 = MM256_SET_M128I(_mm_shuffle_epi8(values128, _mm_and_si128(_mm_srli_epi16(q4bits_1, 4), m4b)), + _mm_shuffle_epi8(values128, _mm_and_si128(q4bits_1, m4b))); + const __m256i q4b_2 = MM256_SET_M128I(_mm_shuffle_epi8(values128, _mm_and_si128(_mm_srli_epi16(q4bits_2, 4), m4b)), + _mm_shuffle_epi8(values128, _mm_and_si128(q4bits_2, m4b))); + const __m256i p16_1 = mul_add_epi8(q4b_1, q8b_1); + const __m256i p16_2 = mul_add_epi8(q4b_2, q8b_2); + const int16_t ls1 = ((x[ibl].scales_l[ib/2] & 0xf) | ((sh << 4) & 0x30)) - 32; + const int16_t ls2 = ((x[ibl].scales_l[ib/2] >> 4) | ((sh << 2) & 0x30)) - 32; + sh >>= 4; + const __m256i p_1 = _mm256_madd_epi16(p16_1, _mm256_set1_epi16(ls1)); + const __m256i p_2 = _mm256_madd_epi16(p16_2, _mm256_set1_epi16(ls2)); + sumi1 = _mm256_add_epi32(p_1, sumi1); + sumi2 = _mm256_add_epi32(p_2, sumi2); + } + accum = _mm256_fmadd_ps(_mm256_set1_ps(GGML_FP16_TO_FP32(x[ibl].d)*y[ibl].d), + _mm256_cvtepi32_ps(_mm256_add_epi32(sumi1, sumi2)), accum); + } + + *s = hsum_float_8(accum); + +#else + float sumf = 0; + for (int ibl = 0; ibl < nb; ++ibl) { + const float d4d8 = GGML_FP16_TO_FP32(x[ibl].d) * y[ibl].d; + uint16_t h = x[ibl].scales_h; + const uint8_t * qs = x[ibl].qs; + const int8_t * q8 = y[ibl].qs; + for (int ib = 0; ib < QK_K/32; ib += 2) { + const uint8_t ls1 = (x[ibl].scales_l[ib/2] & 0xf) | ((h << 4) & 0x30); + const uint8_t ls2 = (x[ibl].scales_l[ib/2] >> 4) | ((h << 2) & 0x30); + h >>= 4; + const float d1 = d4d8*(ls1 - 32); + const float d2 = d4d8*(ls2 - 32); + int sumi1 = 0, sumi2 = 0; + for (int j = 0; j < 16; ++j) { + sumi1 += q8[j+ 0] * kvalues_iq4nl[qs[j] & 0xf]; + sumi2 += q8[j+16] * kvalues_iq4nl[qs[j] >> 4]; + } + sumf += d1 * (sumi1 + sumi2); + qs += 16; + q8 += 32; + sumi1 = sumi2 = 0; + for (int j = 0; j < 16; ++j) { + sumi1 += q8[j+ 0] * kvalues_iq4nl[qs[j] & 0xf]; + sumi2 += q8[j+16] * kvalues_iq4nl[qs[j] >> 4]; + } + sumf += d2 * (sumi1 + sumi2); + qs += 16; + q8 += 32; + } + } + *s = sumf; +#endif +#endif +} + +// ================================ IQ2 quantization ============================================= + +typedef struct { + uint64_t * grid; + int * map; + uint16_t * neighbours; +} iq2_entry_t; + +static iq2_entry_t iq2_data[4] = { + {NULL, NULL, NULL}, + {NULL, NULL, NULL}, + {NULL, NULL, NULL}, + {NULL, NULL, NULL}, +}; + +static inline int iq2_data_index(enum ggml_type type) { + GGML_ASSERT(type == GGML_TYPE_IQ2_XXS || type == GGML_TYPE_IQ2_XS || type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M || type == GGML_TYPE_IQ2_S); + return type == GGML_TYPE_IQ2_XXS ? 0 : + type == GGML_TYPE_IQ2_XS ? 1 : + type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M ? 2 : 3; +} + +static inline int iq2_grid_size(enum ggml_type type) { + GGML_ASSERT(type == GGML_TYPE_IQ2_XXS || type == GGML_TYPE_IQ2_XS || type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M || type == GGML_TYPE_IQ2_S); + return type == GGML_TYPE_IQ2_XXS ? 256 : + type == GGML_TYPE_IQ2_XS ? 512 : + type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M ? NGRID_IQ1S : 1024; +} + +static int iq2_compare_func(const void * left, const void * right) { + const int * l = (const int *)left; + const int * r = (const int *)right; + return l[0] < r[0] ? -1 : l[0] > r[0] ? 1 : l[1] < r[1] ? -1 : l[1] > r[1] ? 1 : 0; +} + +void iq2xs_init_impl(enum ggml_type type) { + const int gindex = iq2_data_index(type); + const int grid_size = iq2_grid_size(type); + if (iq2_data[gindex].grid) { + return; + } + static const uint16_t kgrid_2bit_256[256] = { + 0, 2, 5, 8, 10, 17, 20, 32, 34, 40, 42, 65, 68, 80, 88, 97, + 100, 128, 130, 138, 162, 257, 260, 272, 277, 320, 388, 408, 512, 514, 546, 642, + 1025, 1028, 1040, 1057, 1060, 1088, 1090, 1096, 1120, 1153, 1156, 1168, 1188, 1280, 1282, 1288, + 1312, 1350, 1385, 1408, 1425, 1545, 1552, 1600, 1668, 1700, 2048, 2053, 2056, 2068, 2088, 2113, + 2116, 2128, 2130, 2184, 2308, 2368, 2562, 2580, 4097, 4100, 4112, 4129, 4160, 4192, 4228, 4240, + 4245, 4352, 4360, 4384, 4432, 4442, 4480, 4644, 4677, 5120, 5128, 5152, 5157, 5193, 5248, 5400, + 5474, 5632, 5654, 6145, 6148, 6160, 6208, 6273, 6400, 6405, 6560, 6737, 8192, 8194, 8202, 8260, + 8289, 8320, 8322, 8489, 8520, 8704, 8706, 9217, 9220, 9232, 9280, 9302, 9472, 9537, 9572, 9872, + 10248, 10272, 10388, 10820, 16385, 16388, 16400, 16408, 16417, 16420, 16448, 16456, 16470, 16480, 16513, 16516, + 16528, 16640, 16672, 16737, 16768, 16773, 16897, 16912, 16968, 16982, 17000, 17408, 17416, 17440, 17536, 17561, + 17682, 17700, 17920, 18433, 18436, 18448, 18496, 18501, 18688, 18776, 18785, 18818, 19013, 19088, 20480, 20488, + 20497, 20505, 20512, 20608, 20616, 20740, 20802, 20900, 21137, 21648, 21650, 21770, 22017, 22100, 22528, 22545, + 22553, 22628, 22848, 23048, 24580, 24592, 24640, 24680, 24832, 24917, 25112, 25184, 25600, 25605, 25872, 25874, + 25988, 26690, 32768, 32770, 32778, 32833, 32898, 33028, 33048, 33088, 33297, 33793, 33796, 33808, 33813, 33856, + 33888, 34048, 34118, 34196, 34313, 34368, 34400, 34818, 35076, 35345, 36868, 36880, 36900, 36928, 37025, 37142, + 37248, 37445, 37888, 37922, 37956, 38225, 39041, 39200, 40962, 41040, 41093, 41225, 41472, 42008, 43088, 43268, + }; + static const uint16_t kgrid_2bit_512[512] = { + 0, 2, 5, 8, 10, 17, 20, 22, 25, 32, 34, 37, 40, 65, 68, 70, + 73, 80, 82, 85, 88, 97, 100, 128, 130, 133, 136, 145, 148, 153, 160, 257, + 260, 262, 265, 272, 274, 277, 280, 282, 289, 292, 320, 322, 325, 328, 337, 340, + 352, 360, 385, 388, 400, 512, 514, 517, 520, 529, 532, 544, 577, 580, 592, 597, + 640, 650, 1025, 1028, 1030, 1033, 1040, 1042, 1045, 1048, 1057, 1060, 1088, 1090, 1093, 1096, + 1105, 1108, 1110, 1120, 1153, 1156, 1168, 1280, 1282, 1285, 1288, 1297, 1300, 1312, 1345, 1348, + 1360, 1377, 1408, 1537, 1540, 1552, 1574, 1600, 1602, 1668, 2048, 2050, 2053, 2056, 2058, 2065, + 2068, 2080, 2085, 2113, 2116, 2128, 2136, 2176, 2208, 2218, 2305, 2308, 2320, 2368, 2433, 2441, + 2560, 2592, 2600, 2710, 2720, 4097, 4100, 4102, 4105, 4112, 4114, 4117, 4120, 4129, 4132, 4160, + 4162, 4165, 4168, 4177, 4180, 4192, 4202, 4225, 4228, 4240, 4352, 4354, 4357, 4360, 4369, 4372, + 4384, 4417, 4420, 4432, 4480, 4500, 4502, 4609, 4612, 4614, 4624, 4672, 4704, 5120, 5122, 5125, + 5128, 5137, 5140, 5152, 5185, 5188, 5193, 5200, 5220, 5248, 5377, 5380, 5392, 5440, 5632, 5652, + 5705, 6145, 6148, 6160, 6162, 6208, 6228, 6278, 6400, 6405, 6502, 6737, 6825, 8192, 8194, 8197, + 8200, 8202, 8209, 8212, 8224, 8257, 8260, 8272, 8320, 8352, 8449, 8452, 8464, 8512, 8520, 8549, + 8704, 8738, 8832, 8872, 9217, 9220, 9232, 9257, 9280, 9472, 9537, 9554, 9625, 9729, 9754, 9894, + 10240, 10248, 10250, 10272, 10325, 10376, 10402, 10600, 10640, 10760, 10784, 10882, 10888, 10890, 16385, 16388, + 16390, 16393, 16400, 16402, 16405, 16408, 16417, 16420, 16448, 16450, 16453, 16456, 16458, 16465, 16468, 16480, + 16485, 16513, 16516, 16528, 16640, 16642, 16645, 16648, 16657, 16660, 16672, 16705, 16708, 16720, 16768, 16773, + 16802, 16897, 16900, 16912, 16914, 16937, 16960, 17408, 17410, 17413, 17416, 17425, 17428, 17433, 17440, 17473, + 17476, 17488, 17536, 17556, 17665, 17668, 17680, 17700, 17728, 17818, 17920, 17930, 17988, 18000, 18433, 18436, + 18448, 18496, 18501, 18516, 18530, 18688, 18705, 18756, 18768, 18793, 18948, 20480, 20482, 20485, 20488, 20497, + 20500, 20512, 20520, 20545, 20548, 20560, 20608, 20737, 20740, 20752, 20757, 20800, 20802, 20992, 21060, 21162, + 21505, 21508, 21520, 21537, 21568, 21600, 21633, 21665, 21760, 21768, 21888, 21896, 22049, 22120, 22177, 22528, + 22548, 22593, 22608, 22681, 22810, 22848, 22850, 23173, 24577, 24580, 24592, 24640, 24660, 24674, 24710, 24745, + 24832, 25124, 25162, 25234, 25600, 25622, 25872, 25920, 25925, 26020, 26625, 26730, 26917, 27142, 27220, 27234, + 32768, 32770, 32773, 32776, 32785, 32788, 32800, 32810, 32833, 32836, 32848, 32896, 32898, 32936, 32938, 33025, + 33028, 33030, 33040, 33088, 33105, 33113, 33280, 33312, 33408, 33410, 33440, 33448, 33793, 33796, 33808, 33810, + 33813, 33856, 33888, 33929, 34048, 34116, 34213, 34328, 34410, 34816, 34824, 34853, 34906, 34944, 34946, 34984, + 35078, 35362, 35456, 35464, 35478, 35496, 36865, 36868, 36880, 36928, 36950, 36996, 37120, 37154, 37220, 37462, + 37513, 37888, 37893, 37956, 37968, 37976, 38185, 38288, 38290, 38465, 38993, 39078, 39241, 39445, 39520, 40960, + 40962, 40968, 40970, 40992, 41002, 41120, 41297, 41305, 41382, 41472, 41474, 41480, 41514, 41600, 41632, 42048, + 42133, 42597, 42648, 43018, 43040, 43042, 43048, 43168, 43176, 43268, 43396, 43398, 43560, 43562, 43665, 43690, + }; + static const uint16_t kgrid_1bit_2048[NGRID_IQ1S] = { + 0, 2, 5, 8, 10, 17, 21, 32, 34, 40, 42, 69, 81, 84, 86, 101, + 128, 130, 136, 138, 149, 160, 162, 168, 170, 260, 261, 273, 276, 278, 281, 282, + 293, 321, 326, 329, 338, 341, 346, 353, 356, 358, 360, 389, 401, 404, 406, 421, + 512, 514, 520, 522, 533, 544, 546, 552, 554, 581, 593, 601, 612, 617, 640, 642, + 648, 650, 657, 661, 665, 672, 674, 680, 682, 1041, 1044, 1046, 1061, 1089, 1097, 1109, + 1114, 1124, 1125, 1169, 1177, 1189, 1281, 1284, 1285, 1286, 1301, 1304, 1306, 1321, 1344, 1349, + 1354, 1360, 1361, 1364, 1365, 1366, 1369, 1376, 1378, 1381, 1384, 1386, 1409, 1425, 1429, 1432, + 1434, 1441, 1444, 1445, 1446, 1449, 1556, 1561, 1601, 1604, 1616, 1618, 1621, 1624, 1632, 1633, + 1638, 1641, 1669, 1681, 1684, 1689, 2048, 2050, 2056, 2058, 2069, 2080, 2082, 2088, 2090, 2117, + 2129, 2134, 2149, 2176, 2178, 2184, 2186, 2197, 2208, 2210, 2216, 2218, 2309, 2321, 2324, 2329, + 2340, 2341, 2369, 2384, 2385, 2389, 2401, 2404, 2409, 2449, 2452, 2454, 2457, 2469, 2560, 2562, + 2568, 2570, 2581, 2592, 2594, 2600, 2602, 2629, 2641, 2649, 2657, 2661, 2688, 2690, 2693, 2696, + 2698, 2709, 2720, 2722, 2728, 2730, 4112, 4113, 4116, 4121, 4132, 4133, 4161, 4164, 4176, 4181, + 4184, 4193, 4196, 4197, 4201, 4241, 4244, 4246, 4257, 4261, 4353, 4356, 4358, 4361, 4368, 4370, + 4373, 4376, 4385, 4388, 4393, 4421, 4426, 4432, 4433, 4434, 4436, 4437, 4438, 4441, 4448, 4453, + 4484, 4498, 4501, 4513, 4516, 4625, 4628, 4630, 4645, 4672, 4678, 4681, 4690, 4693, 4696, 4698, + 4708, 4710, 4741, 4753, 4756, 4758, 4773, 5121, 5126, 5129, 5140, 5141, 5144, 5145, 5153, 5158, + 5185, 5189, 5190, 5192, 5194, 5201, 5204, 5205, 5206, 5209, 5218, 5221, 5224, 5252, 5257, 5264, + 5268, 5269, 5272, 5273, 5274, 5281, 5284, 5285, 5289, 5378, 5381, 5386, 5393, 5396, 5397, 5398, + 5401, 5408, 5410, 5413, 5416, 5418, 5441, 5444, 5445, 5446, 5457, 5458, 5460, 5461, 5462, 5465, + 5466, 5473, 5476, 5477, 5478, 5481, 5504, 5506, 5508, 5509, 5512, 5514, 5520, 5521, 5524, 5525, + 5526, 5529, 5530, 5536, 5538, 5541, 5633, 5636, 5637, 5638, 5653, 5654, 5656, 5658, 5665, 5670, + 5696, 5698, 5700, 5701, 5704, 5706, 5713, 5717, 5718, 5720, 5721, 5729, 5732, 5733, 5736, 5737, + 5738, 5766, 5770, 5778, 5781, 5796, 5801, 6161, 6166, 6181, 6209, 6212, 6214, 6217, 6224, 6229, + 6232, 6234, 6240, 6241, 6244, 6246, 6249, 6277, 6289, 6292, 6309, 6416, 6418, 6421, 6426, 6433, + 6437, 6466, 6468, 6469, 6472, 6481, 6484, 6485, 6486, 6489, 6490, 6496, 6501, 6506, 6537, 6545, + 6546, 6549, 6552, 6561, 6566, 6569, 6665, 6678, 6692, 6694, 6724, 6726, 6729, 6736, 6738, 6741, + 6744, 6753, 6758, 6761, 6789, 6801, 6806, 6810, 8192, 8194, 8200, 8202, 8213, 8224, 8226, 8229, + 8232, 8234, 8261, 8273, 8281, 8289, 8293, 8320, 8322, 8328, 8330, 8341, 8352, 8354, 8357, 8360, + 8362, 8453, 8465, 8468, 8473, 8485, 8514, 8516, 8521, 8533, 8536, 8538, 8545, 8548, 8549, 8550, + 8581, 8592, 8598, 8601, 8613, 8705, 8712, 8714, 8721, 8725, 8736, 8738, 8744, 8746, 8773, 8785, + 8790, 8793, 8805, 8833, 8840, 8842, 8849, 8853, 8864, 8866, 8872, 8874, 9221, 9236, 9238, 9241, + 9253, 9284, 9285, 9286, 9289, 9298, 9301, 9304, 9306, 9318, 9349, 9361, 9364, 9369, 9377, 9381, + 9481, 9493, 9505, 9513, 9536, 9541, 9544, 9553, 9556, 9557, 9561, 9570, 9573, 9576, 9609, 9616, + 9620, 9621, 9624, 9626, 9633, 9636, 9638, 9641, 9733, 9744, 9746, 9753, 9765, 9793, 9801, 9813, + 9824, 9825, 9833, 9860, 9862, 9872, 9882, 10240, 10242, 10248, 10250, 10261, 10272, 10274, 10280, 10282, + 10309, 10321, 10324, 10341, 10368, 10370, 10376, 10378, 10400, 10402, 10408, 10410, 10505, 10513, 10516, 10521, + 10533, 10566, 10569, 10578, 10581, 10593, 10596, 10598, 10601, 10629, 10640, 10646, 10649, 10660, 10661, 10752, + 10754, 10760, 10762, 10784, 10786, 10792, 10794, 10821, 10833, 10838, 10841, 10853, 10880, 10882, 10888, 10890, + 10901, 10912, 10914, 10920, 10922, 16389, 16401, 16406, 16421, 16457, 16466, 16469, 16472, 16474, 16481, 16484, + 16486, 16532, 16537, 16545, 16550, 16640, 16641, 16644, 16646, 16649, 16658, 16661, 16662, 16664, 16666, 16673, + 16678, 16681, 16709, 16712, 16714, 16721, 16724, 16725, 16726, 16729, 16730, 16741, 16744, 16746, 16769, 16772, + 16774, 16784, 16786, 16789, 16800, 16801, 16802, 16901, 16913, 16916, 16918, 16933, 16961, 16978, 16981, 16986, + 16996, 17001, 17033, 17044, 17061, 17409, 17429, 17433, 17449, 17477, 17480, 17482, 17489, 17492, 17493, 17494, + 17505, 17506, 17509, 17512, 17514, 17537, 17542, 17545, 17552, 17554, 17557, 17568, 17569, 17577, 17665, 17666, + 17669, 17674, 17681, 17684, 17685, 17686, 17689, 17696, 17701, 17706, 17729, 17732, 17733, 17734, 17737, 17744, + 17745, 17748, 17749, 17750, 17752, 17753, 17761, 17764, 17765, 17766, 17769, 17794, 17796, 17797, 17800, 17809, + 17812, 17813, 17814, 17817, 17818, 17829, 17832, 17834, 17921, 17925, 17929, 17940, 17941, 17944, 17946, 17953, + 17956, 17961, 17984, 17986, 17989, 17992, 18000, 18001, 18002, 18005, 18006, 18009, 18018, 18021, 18024, 18049, + 18053, 18058, 18068, 18069, 18081, 18084, 18086, 18437, 18449, 18453, 18458, 18469, 18498, 18505, 18512, 18517, + 18520, 18529, 18532, 18534, 18537, 18565, 18577, 18580, 18582, 18585, 18597, 18689, 18693, 18694, 18698, 18704, + 18708, 18709, 18712, 18721, 18724, 18726, 18752, 18757, 18762, 18769, 18770, 18772, 18773, 18774, 18777, 18784, + 18786, 18789, 18790, 18794, 18822, 18825, 18834, 18837, 18838, 18840, 18849, 18852, 18854, 18857, 18966, 19012, + 19014, 19017, 19029, 19032, 19034, 19044, 19049, 19092, 19109, 20481, 20484, 20485, 20486, 20489, 20498, 20501, + 20506, 20513, 20516, 20521, 20544, 20549, 20552, 20561, 20564, 20565, 20566, 20569, 20581, 20584, 20614, 20617, + 20629, 20632, 20640, 20641, 20646, 20649, 20741, 20744, 20745, 20746, 20753, 20756, 20757, 20758, 20760, 20761, + 20768, 20773, 20774, 20776, 20778, 20801, 20804, 20805, 20806, 20809, 20816, 20817, 20818, 20820, 20821, 20822, + 20824, 20825, 20826, 20833, 20836, 20837, 20838, 20841, 20866, 20869, 20881, 20884, 20885, 20886, 20889, 20896, + 20901, 20906, 20993, 20998, 21010, 21013, 21018, 21025, 21028, 21058, 21061, 21066, 21073, 21076, 21077, 21078, + 21081, 21090, 21093, 21125, 21136, 21138, 21141, 21145, 21146, 21156, 21508, 21509, 21521, 21524, 21525, 21526, + 21528, 21529, 21537, 21541, 21544, 21546, 21569, 21572, 21573, 21574, 21577, 21578, 21584, 21585, 21588, 21589, + 21590, 21592, 21593, 21594, 21601, 21602, 21604, 21605, 21606, 21609, 21632, 21640, 21642, 21649, 21652, 21653, + 21654, 21657, 21665, 21668, 21669, 21674, 21761, 21762, 21764, 21765, 21766, 21769, 21776, 21777, 21778, 21780, + 21781, 21782, 21785, 21786, 21793, 21796, 21797, 21798, 21801, 21824, 21825, 21826, 21828, 21829, 21830, 21832, + 21833, 21840, 21841, 21842, 21844, 21845, 21846, 21848, 21849, 21850, 21856, 21857, 21860, 21861, 21862, 21864, + 21865, 21866, 21889, 21892, 21893, 21897, 21898, 21904, 21905, 21908, 21909, 21910, 21912, 21913, 21921, 21924, + 21925, 21926, 21929, 22016, 22017, 22018, 22020, 22022, 22024, 22025, 22033, 22036, 22037, 22040, 22041, 22048, + 22049, 22050, 22052, 22053, 22054, 22056, 22057, 22081, 22085, 22086, 22088, 22089, 22090, 22096, 22097, 22098, + 22100, 22101, 22102, 22104, 22105, 22106, 22113, 22116, 22117, 22121, 22146, 22149, 22150, 22152, 22153, 22154, + 22161, 22165, 22170, 22178, 22181, 22182, 22184, 22185, 22532, 22533, 22534, 22537, 22544, 22549, 22552, 22561, + 22570, 22597, 22600, 22602, 22609, 22612, 22613, 22614, 22616, 22617, 22624, 22626, 22628, 22629, 22658, 22665, + 22672, 22674, 22677, 22680, 22689, 22697, 22785, 22786, 22789, 22794, 22801, 22804, 22805, 22806, 22809, 22821, + 22849, 22852, 22853, 22854, 22857, 22864, 22865, 22866, 22868, 22869, 22870, 22872, 22873, 22874, 22881, 22884, + 22885, 22886, 22889, 22913, 22917, 22921, 22929, 22932, 22933, 22934, 22936, 22937, 22949, 23044, 23048, 23061, + 23066, 23072, 23077, 23078, 23081, 23109, 23112, 23113, 23121, 23125, 23126, 23128, 23129, 23138, 23141, 23144, + 23146, 23169, 23178, 23186, 23189, 23190, 23192, 23194, 23201, 24581, 24596, 24598, 24601, 24613, 24644, 24656, + 24661, 24662, 24664, 24666, 24673, 24676, 24678, 24681, 24705, 24726, 24741, 24833, 24836, 24838, 24841, 24850, + 24853, 24865, 24866, 24870, 24873, 24901, 24905, 24913, 24917, 24918, 24921, 24933, 24934, 24938, 24964, 24970, + 24978, 24981, 24993, 24998, 25001, 25105, 25110, 25113, 25152, 25153, 25158, 25173, 25174, 25176, 25184, 25221, + 25233, 25238, 25253, 25617, 25618, 25621, 25622, 25626, 25633, 25638, 25641, 25664, 25666, 25669, 25672, 25674, + 25681, 25684, 25685, 25686, 25689, 25690, 25696, 25698, 25701, 25732, 25733, 25737, 25744, 25746, 25748, 25749, + 25750, 25752, 25754, 25761, 25764, 25769, 25861, 25864, 25866, 25873, 25877, 25878, 25881, 25924, 25925, 25926, + 25929, 25936, 25937, 25940, 25941, 25942, 25945, 25953, 25956, 25957, 25958, 25961, 25990, 25993, 25994, 26001, + 26005, 26006, 26009, 26010, 26018, 26021, 26022, 26024, 26114, 26121, 26133, 26144, 26150, 26152, 26153, 26176, + 26181, 26184, 26186, 26193, 26196, 26197, 26198, 26200, 26202, 26208, 26213, 26216, 26240, 26242, 26245, 26250, + 26260, 26262, 26264, 26265, 26272, 26276, 26278, 26282, 26646, 26649, 26661, 26689, 26706, 26709, 26714, 26721, + 26729, 26757, 26769, 26776, 26790, 26881, 26884, 26896, 26901, 26913, 26916, 26918, 26921, 26944, 26945, 26949, + 26950, 26952, 26961, 26964, 26965, 26966, 26969, 26976, 26981, 26986, 27010, 27012, 27018, 27029, 27041, 27044, + 27045, 27049, 27153, 27158, 27160, 27201, 27204, 27209, 27216, 27221, 27224, 27226, 27236, 27237, 27241, 27270, + 27284, 27288, 27290, 27302, 32768, 32770, 32776, 32778, 32800, 32802, 32808, 32810, 32837, 32848, 32849, 32852, + 32854, 32857, 32869, 32896, 32898, 32904, 32906, 32917, 32928, 32930, 32936, 32938, 33029, 33041, 33044, 33046, + 33049, 33061, 33089, 33092, 33097, 33104, 33106, 33109, 33110, 33112, 33113, 33124, 33126, 33129, 33157, 33161, + 33172, 33174, 33177, 33189, 33280, 33282, 33288, 33290, 33301, 33312, 33314, 33320, 33322, 33361, 33364, 33369, + 33381, 33408, 33410, 33416, 33418, 33429, 33440, 33442, 33448, 33450, 33812, 33817, 33857, 33860, 33873, 33877, + 33882, 33889, 33892, 33897, 33940, 33945, 34049, 34057, 34066, 34069, 34074, 34086, 34089, 34112, 34113, 34117, + 34120, 34129, 34132, 34133, 34134, 34137, 34138, 34149, 34150, 34152, 34154, 34177, 34180, 34182, 34185, 34192, + 34194, 34197, 34200, 34214, 34321, 34326, 34329, 34341, 34369, 34372, 34377, 34378, 34384, 34389, 34393, 34394, + 34401, 34406, 34410, 34437, 34449, 34458, 34468, 34816, 34818, 34824, 34826, 34837, 34848, 34850, 34856, 34858, + 34881, 34885, 34897, 34900, 34905, 34917, 34921, 34944, 34946, 34952, 34954, 34965, 34976, 34978, 34984, 34986, + 35077, 35078, 35089, 35092, 35094, 35109, 35137, 35140, 35142, 35145, 35152, 35154, 35157, 35162, 35169, 35172, + 35205, 35222, 35225, 35237, 35328, 35330, 35336, 35338, 35349, 35360, 35362, 35368, 35370, 35397, 35409, 35412, + 35414, 35456, 35458, 35464, 35466, 35477, 35488, 35490, 35496, 35498, 36869, 36881, 36886, 36888, 36889, 36901, + 36929, 36934, 36937, 36949, 36952, 36954, 36969, 36970, 36997, 37009, 37012, 37014, 37017, 37029, 37121, 37124, + 37126, 37129, 37136, 37141, 37144, 37146, 37153, 37156, 37158, 37161, 37184, 37189, 37200, 37201, 37204, 37205, + 37206, 37209, 37218, 37221, 37252, 37254, 37266, 37269, 37272, 37281, 37284, 37286, 37289, 37381, 37393, 37396, + 37401, 37413, 37444, 37446, 37449, 37456, 37458, 37461, 37464, 37478, 37481, 37509, 37524, 37526, 37545, 37889, + 37892, 37894, 37904, 37909, 37912, 37926, 37952, 37962, 37969, 37972, 37973, 37974, 37976, 37977, 37984, 37985, + 37986, 37989, 38020, 38022, 38034, 38036, 38037, 38040, 38049, 38057, 38144, 38149, 38152, 38154, 38160, 38161, + 38164, 38165, 38166, 38169, 38177, 38181, 38185, 38186, 38209, 38212, 38213, 38214, 38217, 38224, 38225, 38226, + 38228, 38229, 38230, 38232, 38233, 38234, 38241, 38244, 38245, 38246, 38249, 38273, 38277, 38280, 38289, 38290, + 38292, 38293, 38294, 38297, 38298, 38304, 38306, 38309, 38312, 38314, 38401, 38404, 38416, 38421, 38425, 38432, + 38438, 38441, 38469, 38472, 38473, 38481, 38482, 38485, 38486, 38489, 38501, 38504, 38530, 38532, 38537, 38538, + 38546, 38548, 38549, 38564, 38566, 38569, 38917, 38934, 38937, 38949, 38977, 38982, 38992, 38994, 38997, 38998, + 39002, 39012, 39013, 39045, 39057, 39062, 39065, 39077, 39172, 39174, 39177, 39184, 39186, 39189, 39192, 39194, + 39200, 39201, 39204, 39206, 39232, 39234, 39237, 39240, 39242, 39249, 39252, 39253, 39254, 39257, 39266, 39269, + 39270, 39274, 39297, 39300, 39312, 39314, 39317, 39322, 39329, 39334, 39429, 39445, 39461, 39492, 39494, 39497, + 39504, 39509, 39512, 39521, 39557, 39569, 39572, 39573, 39574, 40960, 40962, 40968, 40970, 40981, 40992, 40994, + 41000, 41002, 41029, 41041, 41044, 41046, 41049, 41088, 41090, 41096, 41098, 41109, 41120, 41122, 41128, 41130, + 41221, 41225, 41233, 41236, 41238, 41241, 41242, 41286, 41289, 41297, 41301, 41304, 41306, 41313, 41316, 41349, + 41360, 41362, 41366, 41369, 41474, 41480, 41482, 41488, 41497, 41506, 41512, 41514, 41541, 41553, 41558, 41561, + 41573, 41600, 41602, 41608, 41610, 41621, 41632, 41634, 41640, 41642, 42009, 42021, 42049, 42052, 42064, 42068, + 42069, 42072, 42074, 42081, 42085, 42086, 42088, 42089, 42117, 42246, 42249, 42256, 42258, 42261, 42264, 42278, + 42281, 42306, 42309, 42321, 42324, 42325, 42326, 42329, 42341, 42346, 42369, 42372, 42373, 42374, 42377, 42386, + 42389, 42392, 42501, 42513, 42518, 42522, 42529, 42533, 42564, 42566, 42570, 42578, 42581, 42582, 42584, 42592, + 42594, 42630, 42640, 42645, 42646, 42649, 42657, 42660, 42662, 43008, 43010, 43016, 43018, 43040, 43042, 43048, + 43050, 43089, 43092, 43094, 43097, 43136, 43138, 43144, 43146, 43157, 43168, 43170, 43176, 43178, 43269, 43284, + 43289, 43297, 43301, 43329, 43344, 43349, 43354, 43361, 43366, 43369, 43408, 43414, 43520, 43522, 43528, 43530, + 43552, 43554, 43560, 43562, 43601, 43604, 43606, 43648, 43650, 43656, 43658, 43669, 43680, 43682, 43688, 43690, + }; + static const uint16_t kgrid_2bit_1024[1024] = { + 0, 2, 5, 8, 10, 17, 20, 22, 25, 32, 34, 37, 40, 65, 68, 70, + 73, 80, 82, 85, 88, 97, 100, 102, 105, 128, 130, 133, 136, 145, 148, 160, + 165, 170, 257, 260, 262, 265, 272, 274, 277, 280, 289, 292, 320, 322, 325, 328, + 337, 340, 342, 345, 352, 357, 360, 385, 388, 400, 402, 405, 417, 420, 512, 514, + 517, 520, 529, 532, 544, 554, 577, 580, 582, 585, 592, 597, 640, 645, 650, 660, + 674, 1025, 1028, 1030, 1033, 1040, 1042, 1045, 1048, 1057, 1060, 1062, 1065, 1088, 1090, 1093, + 1096, 1098, 1105, 1108, 1110, 1113, 1120, 1122, 1125, 1153, 1156, 1158, 1161, 1168, 1173, 1176, + 1185, 1188, 1280, 1282, 1285, 1288, 1290, 1297, 1300, 1302, 1305, 1312, 1317, 1320, 1345, 1348, + 1350, 1353, 1360, 1362, 1365, 1368, 1377, 1380, 1408, 1410, 1413, 1416, 1425, 1428, 1440, 1537, + 1540, 1542, 1545, 1552, 1557, 1600, 1605, 1608, 1617, 1620, 1632, 1665, 1668, 1680, 2048, 2050, + 2053, 2056, 2065, 2068, 2070, 2073, 2080, 2085, 2090, 2113, 2116, 2118, 2121, 2128, 2130, 2133, + 2136, 2145, 2148, 2176, 2181, 2196, 2218, 2305, 2308, 2320, 2322, 2325, 2328, 2337, 2368, 2373, + 2376, 2385, 2388, 2400, 2433, 2448, 2560, 2577, 2580, 2594, 2600, 2602, 2640, 2713, 4097, 4100, + 4102, 4105, 4112, 4114, 4117, 4120, 4129, 4132, 4134, 4160, 4162, 4165, 4168, 4177, 4180, 4182, + 4185, 4192, 4194, 4197, 4200, 4225, 4228, 4230, 4240, 4245, 4248, 4257, 4260, 4352, 4354, 4357, + 4360, 4362, 4369, 4372, 4374, 4377, 4384, 4386, 4389, 4392, 4417, 4420, 4422, 4425, 4432, 4434, + 4437, 4440, 4449, 4452, 4480, 4482, 4485, 4488, 4497, 4500, 4609, 4612, 4617, 4624, 4629, 4641, + 4644, 4672, 4677, 4689, 4692, 4737, 4740, 4752, 5120, 5122, 5125, 5128, 5137, 5140, 5142, 5145, + 5152, 5157, 5160, 5185, 5188, 5190, 5193, 5200, 5202, 5205, 5208, 5217, 5220, 5248, 5250, 5253, + 5256, 5265, 5268, 5280, 5377, 5380, 5382, 5385, 5392, 5394, 5397, 5400, 5409, 5412, 5440, 5442, + 5445, 5448, 5457, 5460, 5472, 5505, 5508, 5520, 5632, 5637, 5640, 5649, 5652, 5664, 5697, 5700, + 5712, 5760, 5802, 6145, 6148, 6150, 6153, 6160, 6165, 6168, 6177, 6208, 6210, 6213, 6216, 6225, + 6228, 6240, 6273, 6276, 6400, 6402, 6405, 6408, 6417, 6420, 6432, 6465, 6468, 6480, 6505, 6562, + 6660, 6672, 6720, 6742, 8192, 8194, 8197, 8200, 8209, 8212, 8214, 8217, 8224, 8229, 8234, 8257, + 8260, 8272, 8274, 8277, 8292, 8320, 8330, 8340, 8362, 8449, 8452, 8464, 8466, 8469, 8481, 8512, + 8514, 8517, 8529, 8532, 8544, 8577, 8580, 8592, 8704, 8714, 8738, 8744, 8746, 8772, 8784, 8840, + 8842, 8872, 9217, 9220, 9222, 9225, 9232, 9237, 9240, 9249, 9252, 9280, 9282, 9285, 9288, 9297, + 9300, 9312, 9345, 9348, 9360, 9472, 9477, 9480, 9489, 9492, 9504, 9537, 9540, 9552, 9574, 9600, + 9729, 9732, 9744, 9792, 9817, 10240, 10245, 10257, 10260, 10305, 10308, 10320, 10378, 10410, 10497, 10500, + 10512, 10645, 10762, 10786, 10852, 10888, 10890, 16385, 16388, 16390, 16393, 16400, 16402, 16405, 16408, 16410, + 16417, 16420, 16422, 16448, 16450, 16453, 16456, 16458, 16465, 16468, 16470, 16473, 16480, 16482, 16485, 16513, + 16516, 16528, 16533, 16536, 16545, 16548, 16640, 16642, 16645, 16648, 16657, 16660, 16662, 16665, 16672, 16674, + 16677, 16705, 16708, 16710, 16713, 16720, 16722, 16725, 16728, 16737, 16740, 16768, 16770, 16773, 16776, 16785, + 16788, 16800, 16897, 16900, 16912, 16914, 16917, 16920, 16932, 16960, 16965, 16968, 16977, 16980, 16992, 17025, + 17028, 17408, 17410, 17413, 17416, 17418, 17425, 17428, 17430, 17433, 17440, 17442, 17445, 17448, 17473, 17476, + 17478, 17481, 17488, 17490, 17493, 17496, 17505, 17508, 17536, 17538, 17541, 17544, 17553, 17556, 17568, 17665, + 17668, 17670, 17673, 17680, 17682, 17685, 17688, 17697, 17700, 17728, 17730, 17733, 17736, 17745, 17748, 17760, + 17770, 17793, 17796, 17808, 17920, 17922, 17925, 17928, 17937, 17940, 17952, 17985, 17988, 18000, 18048, 18085, + 18433, 18436, 18441, 18448, 18450, 18453, 18456, 18465, 18468, 18496, 18498, 18501, 18504, 18513, 18516, 18528, + 18564, 18576, 18688, 18690, 18693, 18696, 18705, 18708, 18720, 18753, 18756, 18768, 18816, 18838, 18945, 18948, + 18960, 19008, 20480, 20482, 20485, 20488, 20497, 20500, 20502, 20505, 20512, 20514, 20517, 20520, 20545, 20548, + 20550, 20553, 20560, 20562, 20565, 20568, 20577, 20580, 20608, 20610, 20613, 20616, 20625, 20628, 20737, 20740, + 20742, 20745, 20752, 20754, 20757, 20760, 20769, 20772, 20800, 20802, 20805, 20808, 20817, 20820, 20832, 20865, + 20868, 20880, 20992, 20997, 21000, 21009, 21012, 21024, 21057, 21060, 21072, 21097, 21120, 21505, 21508, 21510, + 21513, 21520, 21522, 21525, 21528, 21537, 21540, 21568, 21570, 21573, 21576, 21585, 21588, 21600, 21633, 21636, + 21648, 21760, 21762, 21765, 21768, 21777, 21780, 21792, 21825, 21828, 21840, 21888, 22017, 22020, 22032, 22054, + 22080, 22528, 22530, 22533, 22536, 22545, 22548, 22560, 22593, 22596, 22608, 22618, 22656, 22785, 22788, 22800, + 22848, 23040, 23065, 23173, 23208, 24577, 24580, 24582, 24592, 24594, 24597, 24600, 24609, 24612, 24640, 24645, + 24648, 24657, 24660, 24672, 24708, 24720, 24832, 24834, 24837, 24840, 24849, 24852, 24864, 24897, 24900, 24912, + 24960, 24985, 25092, 25104, 25152, 25174, 25249, 25600, 25605, 25608, 25617, 25620, 25632, 25665, 25668, 25680, + 25728, 25857, 25860, 25872, 25920, 25930, 25960, 26002, 26112, 26260, 26625, 26628, 26640, 26725, 26776, 26880, + 26922, 27202, 27297, 32768, 32770, 32773, 32776, 32785, 32788, 32793, 32800, 32805, 32833, 32836, 32848, 32850, + 32853, 32856, 32865, 32896, 32901, 32913, 32916, 33025, 33028, 33033, 33040, 33042, 33045, 33048, 33057, 33060, + 33088, 33090, 33093, 33096, 33105, 33108, 33153, 33156, 33168, 33193, 33280, 33285, 33290, 33297, 33300, 33345, + 33348, 33360, 33793, 33796, 33798, 33801, 33808, 33810, 33813, 33816, 33825, 33856, 33858, 33861, 33864, 33873, + 33876, 33888, 33921, 33924, 33936, 34048, 34050, 34053, 34056, 34065, 34068, 34080, 34113, 34116, 34128, 34176, + 34186, 34305, 34308, 34320, 34345, 34368, 34816, 34821, 34833, 34836, 34881, 34884, 34896, 34978, 35073, 35076, + 35136, 35173, 35362, 35416, 35418, 35458, 35490, 36865, 36868, 36873, 36880, 36882, 36885, 36888, 36900, 36928, + 36930, 36933, 36936, 36945, 36948, 36960, 36993, 36996, 37008, 37120, 37125, 37137, 37140, 37185, 37188, 37200, + 37210, 37377, 37380, 37392, 37440, 37542, 37888, 37890, 37893, 37896, 37905, 37908, 37920, 37953, 37956, 37968, + 38016, 38038, 38145, 38148, 38160, 38208, 38296, 38305, 38400, 38470, 38500, 38913, 38916, 38928, 38950, 38976, + 39081, 39168, 39241, 39250, 39568, 40960, 40965, 40970, 40980, 40994, 41002, 41025, 41028, 41040, 41122, 41130, + 41280, 41317, 41474, 41482, 41506, 41512, 41514, 41602, 41608, 41610, 41640, 41985, 41988, 42000, 42048, 42121, + 42148, 42240, 42265, 42577, 43018, 43048, 43170, 43348, 43398, 43528, 43530, 43552, 43554, 43560, 43656, 43690, + }; + + const int kmap_size = 43692; + //const int nwant = type == GGML_TYPE_IQ1_S ? 3 : 2; + const int nwant = type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M ? 3 : type == GGML_TYPE_IQ2_S ? 1 : 2; + const uint16_t * kgrid = type == GGML_TYPE_IQ2_XXS ? kgrid_2bit_256 : + type == GGML_TYPE_IQ2_XS ? kgrid_2bit_512 : + type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M ? kgrid_1bit_2048 : kgrid_2bit_1024; + uint64_t * kgrid_q2xs; + int * kmap_q2xs; + uint16_t * kneighbors_q2xs; + + //printf("================================================================= %s(grid_size = %d)\n", __func__, grid_size); + uint64_t * the_grid = (uint64_t *)malloc(grid_size*sizeof(uint64_t)); + for (int k = 0; k < grid_size; ++k) { + int8_t * pos = (int8_t *)(the_grid + k); + for (int i = 0; i < 8; ++i) { + int l = (kgrid[k] >> 2*i) & 0x3; + pos[i] = 2*l + 1; + } + } + kgrid_q2xs = the_grid; + iq2_data[gindex].grid = the_grid; + kmap_q2xs = (int *)malloc(kmap_size*sizeof(int)); + iq2_data[gindex].map = kmap_q2xs; + for (int i = 0; i < kmap_size; ++i) kmap_q2xs[i] = -1; + uint64_t aux64; + uint8_t * aux8 = (uint8_t *)&aux64; + for (int i = 0; i < grid_size; ++i) { + aux64 = kgrid_q2xs[i]; + uint16_t index = 0; + for (int k=0; k<8; ++k) { + uint16_t q = (aux8[k] - 1)/2; + index |= (q << 2*k); + } + kmap_q2xs[index] = i; + } + int8_t pos[8]; + int * dist2 = (int *)malloc(2*grid_size*sizeof(int)); + int num_neighbors = 0, num_not_in_map = 0; + for (int i = 0; i < kmap_size; ++i) { + if (kmap_q2xs[i] >= 0) continue; + ++num_not_in_map; + for (int k = 0; k < 8; ++k) { + int l = (i >> 2*k) & 0x3; + pos[k] = 2*l + 1; + } + for (int j = 0; j < grid_size; ++j) { + const int8_t * pg = (const int8_t *)(kgrid_q2xs + j); + int d2 = 0; + for (int k = 0; k < 8; ++k) d2 += (pg[k] - pos[k])*(pg[k] - pos[k]); + dist2[2*j+0] = d2; + dist2[2*j+1] = j; + } + qsort(dist2, grid_size, 2*sizeof(int), iq2_compare_func); + int n = 0; int d2 = dist2[0]; + int nhave = 1; + for (int j = 0; j < grid_size; ++j) { + if (dist2[2*j] > d2) { + if (nhave == nwant) break; + d2 = dist2[2*j]; + ++nhave; + } + ++n; + } + num_neighbors += n; + } + //printf("%s: %d neighbours in total\n", __func__, num_neighbors); + kneighbors_q2xs = (uint16_t *)malloc((num_neighbors + num_not_in_map)*sizeof(uint16_t)); + iq2_data[gindex].neighbours = kneighbors_q2xs; + int counter = 0; + for (int i = 0; i < kmap_size; ++i) { + if (kmap_q2xs[i] >= 0) continue; + for (int k = 0; k < 8; ++k) { + int l = (i >> 2*k) & 0x3; + pos[k] = 2*l + 1; + } + for (int j = 0; j < grid_size; ++j) { + const int8_t * pg = (const int8_t *)(kgrid_q2xs + j); + int d2 = 0; + for (int k = 0; k < 8; ++k) d2 += (pg[k] - pos[k])*(pg[k] - pos[k]); + dist2[2*j+0] = d2; + dist2[2*j+1] = j; + } + qsort(dist2, grid_size, 2*sizeof(int), iq2_compare_func); + kmap_q2xs[i] = -(counter + 1); + int d2 = dist2[0]; + uint16_t * start = &kneighbors_q2xs[counter++]; + int n = 0, nhave = 1; + for (int j = 0; j < grid_size; ++j) { + if (dist2[2*j] > d2) { + if (nhave == nwant) break; + d2 = dist2[2*j]; + ++nhave; + } + kneighbors_q2xs[counter++] = dist2[2*j+1]; + ++n; + } + *start = n; + } + free(dist2); +} + +void iq2xs_free_impl(enum ggml_type type) { + GGML_ASSERT(type == GGML_TYPE_IQ2_XXS || type == GGML_TYPE_IQ2_XS || type == GGML_TYPE_IQ1_S || type == GGML_TYPE_IQ1_M || type == GGML_TYPE_IQ2_S); + const int gindex = iq2_data_index(type); + if (iq2_data[gindex].grid) { + free(iq2_data[gindex].grid); iq2_data[gindex].grid = NULL; + free(iq2_data[gindex].map); iq2_data[gindex].map = NULL; + free(iq2_data[gindex].neighbours); iq2_data[gindex].neighbours = NULL; + } +} + +static int iq2_find_best_neighbour(const uint16_t * restrict neighbours, const uint64_t * restrict grid, + const float * restrict xval, const float * restrict weight, float scale, int8_t * restrict L) { + int num_neighbors = neighbours[0]; + GGML_ASSERT(num_neighbors > 0); + float best_d2 = FLT_MAX; + int grid_index = -1; + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float d2 = 0; + for (int i = 0; i < 8; ++i) { + float q = pg[i]; + float diff = scale*q - xval[i]; + d2 += weight[i]*diff*diff; + } + if (d2 < best_d2) { + best_d2 = d2; grid_index = neighbours[j]; + } + } + GGML_ASSERT(grid_index >= 0); + const int8_t * pg = (const int8_t *)(grid + grid_index); + for (int i = 0; i < 8; ++i) L[i] = (pg[i] - 1)/2; + return grid_index; +} + +static void quantize_row_iq2_xxs_impl(const float * restrict x, void * restrict vy, int64_t n, const float * restrict quant_weights) { + + const int gindex = iq2_data_index(GGML_TYPE_IQ2_XXS); + + const uint64_t * kgrid_q2xs = iq2_data[gindex].grid; + const int * kmap_q2xs = iq2_data[gindex].map; + const uint16_t * kneighbors_q2xs = iq2_data[gindex].neighbours; + + GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kgrid_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kmap_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + const int kMaxQ = 3; + + const int64_t nbl = n/QK_K; + + block_iq2_xxs * y = vy; + + float scales[QK_K/32]; + float weight[32]; + float xval[32]; + int8_t L[32]; + int8_t Laux[32]; + float waux[32]; + uint8_t block_signs[4]; + uint32_t q2[2*(QK_K/32)]; + + for (int ibl = 0; ibl < nbl; ++ibl) { + + y[ibl].d = GGML_FP32_TO_FP16(0.f); + memset(q2, 0, QK_K/4); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = sumx2/QK_K; + + for (int ib = 0; ib < QK_K/32; ++ib) { + const float * xb = xbl + 32*ib; + const float * qw = quant_weights + QK_K*ibl + 32*ib; + for (int i = 0; i < 32; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + for (int i = 0; i < 32; ++i) waux[i] = sqrtf(weight[i]); + for (int k = 0; k < 4; ++k) { + int nflip = 0; + uint8_t s = 0; + for (int i = 0; i < 8; ++i) { + if (xb[8*k + i] >= 0) xval[8*k + i] = xb[8*k + i]; + else { + xval[8*k + i] = -xb[8*k + i]; ++nflip; s |= (1 << i); + } + } + if (nflip%2) { + int imin = 0; float min = weight[8*k+imin]*xb[8*k+imin]*xb[8*k+imin]; + for (int i = 1; i < 8; ++i) { + float ax = weight[8*k+i]*xb[8*k+i]*xb[8*k+i]; + if (ax < min) { + min = ax; imin = i; + } + } + xval[8*k+imin] = -xval[8*k+imin]; + s ^= (1 << imin); + } + block_signs[k] = s & 127; + } + float max = xval[0]; + for (int i = 1; i < 32; ++i) max = MAX(max, xval[i]); + if (!max) { + scales[ib] = 0; + memset(L, 0, 32); + continue; + } + float scale = make_qp_quants(32, kMaxQ+1, xval, (uint8_t*)L, weight); + float eff_max = scale*kMaxQ; + float best = 0; + for (int is = -6; is <= 6; ++is) { + float id = (2*kMaxQ-1+is*0.1f)/eff_max; + float this_scale = 1/id; + for (int k = 0; k < 4; ++k) { + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + Laux[8*k+i] = MAX(0, MIN(kMaxQ-1, l)); + } + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (Laux[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, this_scale, Laux + 8*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 32; ++i) { + float w = weight[i]; + float q = 2*Laux[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + scale = sumqx/sumq2; best = scale*sumqx; + memcpy(L, Laux, 32); + } + } + if (scale > 0) { + float id = 1/scale; + for (int k = 0; k < 4; ++k) { + uint16_t u = 0; + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + l = MAX(0, MIN(kMaxQ-1, l)); + u |= (l << 2*i); + } + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, scale, L + 8*k); + } + const int8_t * pg = (const int8_t *)(kgrid_q2xs + grid_index); + for (int i = 0; i < 8; ++i) L[8*k+i] = (pg[i] - 1)/2; + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 32; ++i) { + float w = weight[i]; + float q = 2*L[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0) scale = sumqx/sumq2; + } + if (scale < 0) { + // This should never happen, but just in case, flip scale so that it is positive (we use uint's to encode the scale) + // and correspondingly flip quant signs. + scale = -scale; + for (int k = 0; k < 4; ++k) block_signs[k] = (~block_signs[k]) & 127; + } + for (int k = 0; k < 4; ++k) { + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (L[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + printf("Oops: found point %u not on grid:", u); + for (int i = 0; i < 8; ++i) printf(" %d", L[8*k+i]); + printf("\n"); + GGML_ASSERT(false); + } + q2[2*ib+0] |= (grid_index << 8*k); + q2[2*ib+1] |= (block_signs[k] << 7*k); + } + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + memset(y[ibl].qs, 0, QK_K/4); + continue; + } + + float d = max_scale/31; + y[ibl].d = GGML_FP32_TO_FP16(d); + float id = 1/d; + for (int ib = 0; ib < QK_K/32; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib]-1)); + l = MAX(0, MIN(15, l)); + q2[2*ib+1] |= ((uint32_t)l << 28); + } + memcpy(y[ibl].qs, q2, QK_K/4); + } +} + +static void quantize_row_iq2_xs_impl(const float * restrict x, void * restrict vy, int64_t n, const float * restrict quant_weights) { + + const int gindex = iq2_data_index(GGML_TYPE_IQ2_XS); + + const uint64_t * kgrid_q2xs = iq2_data[gindex].grid; + const int * kmap_q2xs = iq2_data[gindex].map; + const uint16_t * kneighbors_q2xs = iq2_data[gindex].neighbours; + + GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kmap_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kgrid_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + const int kMaxQ = 3; + + const int64_t nbl = n/QK_K; + + block_iq2_xs * y = vy; + + float scales[QK_K/16]; + float weight[16]; + float xval[16]; + int8_t L[16]; + int8_t Laux[16]; + float waux[16]; + bool is_on_grid[2]; + bool is_on_grid_aux[2]; + uint8_t block_signs[2]; + uint16_t q2[2*(QK_K/16)]; + + for (int ibl = 0; ibl < nbl; ++ibl) { + + y[ibl].d = GGML_FP32_TO_FP16(0.f); + memset(q2, 0, QK_K/4); + memset(y[ibl].scales, 0, QK_K/32); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = sumx2/QK_K; + + for (int ib = 0; ib < QK_K/16; ++ib) { + const float * xb = xbl + 16*ib; + const float * qw = quant_weights + QK_K*ibl + 16*ib; + for (int i = 0; i < 16; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + for (int i = 0; i < 16; ++i) waux[i] = sqrtf(weight[i]); + for (int k = 0; k < 2; ++k) { + int nflip = 0; + uint8_t s = 0; + for (int i = 0; i < 8; ++i) { + if (xb[8*k + i] >= 0) xval[8*k + i] = xb[8*k + i]; + else { + xval[8*k + i] = -xb[8*k + i]; ++nflip; s |= (1 << i); + } + } + if (nflip%2) { + int imin = 0; float min = weight[8*k+imin]*xb[8*k+imin]*xb[8*k+imin]; + for (int i = 1; i < 8; ++i) { + float ax = weight[8*k+i]*xb[8*k+i]*xb[8*k+i]; + if (ax < min) { + min = ax; imin = i; + } + } + xval[8*k+imin] = -xval[8*k+imin]; + s ^= (1 << imin); + } + block_signs[k] = s & 127; + } + float max = xval[0]; + for (int i = 1; i < 16; ++i) max = MAX(max, xval[i]); + if (!max) { + scales[ib] = 0; + memset(L, 0, 16); + continue; + } + float best = 0; + float scale = max/(2*kMaxQ-1); + is_on_grid[0] = is_on_grid[1] = true; + for (int is = -9; is <= 9; ++is) { + float id = (2*kMaxQ-1+is*0.1f)/max; + float this_scale = 1/id; + for (int k = 0; k < 2; ++k) { + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + Laux[8*k+i] = MAX(0, MIN(kMaxQ-1, l)); + } + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (Laux[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + is_on_grid_aux[k] = true; + if (grid_index < 0) { + is_on_grid_aux[k] = false; + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, this_scale, Laux + 8*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 16; ++i) { + float w = weight[i]; + float q = 2*Laux[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + scale = sumqx/sumq2; best = scale*sumqx; + for (int i = 0; i < 16; ++i) L[i] = Laux[i]; + for (int k = 0; k < 2; ++k) is_on_grid[k] = is_on_grid_aux[k]; + } + } + int n_not_ongrid = 0; + for (int k = 0; k < 2; ++k) if (!is_on_grid[k]) ++n_not_ongrid; + if (n_not_ongrid > 0 && scale > 0) { + float id = 1/scale; + for (int k = 0; k < 2; ++k) { + if (is_on_grid[k]) continue; + uint16_t u = 0; + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + l = MAX(0, MIN(kMaxQ-1, l)); + u |= (l << 2*i); + L[8*k + i] = l; + } + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, scale, L + 8*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 16; ++i) { + float w = weight[i]; + float q = 2*L[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0) scale = sumqx/sumq2; + } + if (scale < 0) { + scale = -scale; + for (int k = 0; k < 2; ++k) block_signs[k] = (~block_signs[k]) & 127; + } + for (int k = 0; k < 2; ++k) { + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (L[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + printf("Oops: found point %u not on grid:", u); + for (int i = 0; i < 8; ++i) printf(" %d", L[8*k+i]); + printf("\n"); + GGML_ASSERT(false); + } + q2[2*ib+k] = grid_index | (block_signs[k] << 9); + } + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + memset(y[ibl].qs, 0, QK_K/4); + continue; + } + + float d = max_scale/31; + y[ibl].d = GGML_FP32_TO_FP16(d); + float id = 1/d; + for (int ib = 0; ib < QK_K/16; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib]-1)); + l = MAX(0, MIN(15, l)); + if (ib%2 == 0) y[ibl].scales[ib/2] = l; + else y[ibl].scales[ib/2] |= (l << 4); + } + memcpy(y[ibl].qs, q2, QK_K/4); + + } +} + +size_t quantize_iq2_xxs(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq2_xxs_impl(src, qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += nblock*sizeof(block_iq2_xxs); + } + return nrow * nblock * sizeof(block_iq2_xxs); +} + +size_t quantize_iq2_xs(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq2_xs_impl(src, qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += nblock*sizeof(block_iq2_xs); + } + return nrow * nblock * sizeof(block_iq2_xs); +} + +// +// ============================================= 3-bit using D4 lattice +// + +typedef struct { + uint32_t * grid; + int * map; + uint16_t * neighbours; +} iq3_entry_t; + +static iq3_entry_t iq3_data[2] = { + {NULL, NULL, NULL}, + {NULL, NULL, NULL}, +}; + +static inline int iq3_data_index(int grid_size) { + (void)grid_size; + GGML_ASSERT(grid_size == 256 || grid_size == 512); + return grid_size == 256 ? 0 : 1; +} + +static int iq3_compare_func(const void * left, const void * right) { + const int * l = (const int *)left; + const int * r = (const int *)right; + return l[0] < r[0] ? -1 : l[0] > r[0] ? 1 : l[1] < r[1] ? -1 : l[1] > r[1] ? 1 : 0; +} + +void iq3xs_init_impl(int grid_size) { + const int gindex = iq3_data_index(grid_size); + if (iq3_data[gindex].grid) { + return; + } + static const uint16_t kgrid_256[256] = { + 0, 2, 4, 9, 11, 15, 16, 18, 25, 34, 59, 61, 65, 67, 72, 74, + 81, 85, 88, 90, 97, 108, 120, 128, 130, 132, 137, 144, 146, 153, 155, 159, + 169, 175, 189, 193, 199, 200, 202, 213, 248, 267, 287, 292, 303, 315, 317, 321, + 327, 346, 362, 413, 436, 456, 460, 462, 483, 497, 513, 515, 520, 522, 529, 531, + 536, 538, 540, 551, 552, 576, 578, 585, 592, 594, 641, 643, 648, 650, 657, 664, + 698, 704, 706, 720, 729, 742, 758, 769, 773, 808, 848, 852, 870, 889, 901, 978, + 992, 1024, 1026, 1033, 1035, 1040, 1042, 1046, 1049, 1058, 1089, 1091, 1093, 1096, 1098, 1105, + 1112, 1139, 1143, 1144, 1152, 1154, 1161, 1167, 1168, 1170, 1183, 1184, 1197, 1217, 1224, 1228, + 1272, 1276, 1309, 1323, 1347, 1367, 1377, 1404, 1473, 1475, 1486, 1509, 1537, 1544, 1546, 1553, + 1555, 1576, 1589, 1594, 1600, 1602, 1616, 1625, 1636, 1638, 1665, 1667, 1672, 1685, 1706, 1722, + 1737, 1755, 1816, 1831, 1850, 1856, 1862, 1874, 1901, 1932, 1950, 1971, 2011, 2032, 2052, 2063, + 2077, 2079, 2091, 2095, 2172, 2192, 2207, 2208, 2224, 2230, 2247, 2277, 2308, 2345, 2356, 2389, + 2403, 2424, 2501, 2504, 2506, 2520, 2570, 2593, 2616, 2624, 2630, 2646, 2669, 2700, 2714, 2746, + 2754, 2795, 2824, 2835, 2839, 2874, 2882, 2905, 2984, 3028, 3042, 3092, 3108, 3110, 3124, 3153, + 3185, 3215, 3252, 3288, 3294, 3364, 3397, 3434, 3483, 3523, 3537, 3587, 3589, 3591, 3592, 3610, + 3626, 3670, 3680, 3722, 3749, 3754, 3776, 3789, 3803, 3824, 3857, 3873, 3904, 3906, 3924, 3992, + }; + static const uint16_t kgrid_512[512] = { + 0, 1, 2, 5, 7, 8, 9, 10, 12, 14, 16, 17, 21, 27, 32, 34, + 37, 39, 41, 43, 48, 50, 57, 60, 63, 64, 65, 66, 68, 72, 73, 77, + 80, 83, 87, 89, 93, 100, 113, 117, 122, 128, 129, 133, 135, 136, 139, 142, + 145, 149, 152, 156, 162, 165, 167, 169, 171, 184, 187, 195, 201, 205, 208, 210, + 217, 219, 222, 228, 232, 234, 247, 249, 253, 256, 267, 271, 273, 276, 282, 288, + 291, 297, 312, 322, 324, 336, 338, 342, 347, 353, 357, 359, 374, 379, 390, 393, + 395, 409, 426, 441, 448, 450, 452, 464, 466, 470, 475, 488, 492, 512, 513, 514, + 516, 520, 521, 523, 525, 527, 528, 530, 537, 540, 542, 556, 558, 561, 570, 576, + 577, 579, 582, 584, 588, 593, 600, 603, 609, 616, 618, 632, 638, 640, 650, 653, + 655, 656, 660, 666, 672, 675, 685, 688, 698, 705, 708, 711, 712, 715, 721, 727, + 728, 732, 737, 754, 760, 771, 773, 778, 780, 793, 795, 802, 806, 808, 812, 833, + 840, 843, 849, 856, 858, 873, 912, 916, 919, 932, 934, 961, 963, 968, 970, 977, + 989, 993, 1010, 1016, 1024, 1025, 1027, 1029, 1031, 1032, 1034, 1036, 1038, 1041, 1043, 1047, + 1048, 1050, 1057, 1059, 1061, 1064, 1066, 1079, 1080, 1083, 1085, 1088, 1090, 1096, 1099, 1103, + 1106, 1109, 1113, 1116, 1122, 1129, 1153, 1156, 1159, 1169, 1171, 1176, 1183, 1185, 1195, 1199, + 1209, 1212, 1216, 1218, 1221, 1225, 1234, 1236, 1241, 1243, 1250, 1256, 1270, 1281, 1287, 1296, + 1299, 1306, 1309, 1313, 1338, 1341, 1348, 1353, 1362, 1375, 1376, 1387, 1400, 1408, 1410, 1415, + 1425, 1453, 1457, 1477, 1481, 1494, 1496, 1507, 1512, 1538, 1545, 1547, 1549, 1551, 1554, 1561, + 1563, 1565, 1570, 1572, 1575, 1577, 1587, 1593, 1601, 1603, 1605, 1612, 1617, 1619, 1632, 1648, + 1658, 1662, 1664, 1674, 1680, 1690, 1692, 1704, 1729, 1736, 1740, 1745, 1747, 1751, 1752, 1761, + 1763, 1767, 1773, 1787, 1795, 1801, 1806, 1810, 1817, 1834, 1840, 1844, 1857, 1864, 1866, 1877, + 1882, 1892, 1902, 1915, 1934, 1953, 1985, 1987, 2000, 2002, 2013, 2048, 2052, 2058, 2064, 2068, + 2071, 2074, 2081, 2088, 2104, 2114, 2119, 2121, 2123, 2130, 2136, 2141, 2147, 2153, 2157, 2177, + 2179, 2184, 2189, 2193, 2203, 2208, 2223, 2226, 2232, 2244, 2249, 2251, 2256, 2258, 2265, 2269, + 2304, 2306, 2324, 2335, 2336, 2361, 2373, 2375, 2385, 2418, 2443, 2460, 2480, 2504, 2509, 2520, + 2531, 2537, 2562, 2568, 2572, 2578, 2592, 2596, 2599, 2602, 2614, 2620, 2625, 2627, 2629, 2634, + 2641, 2650, 2682, 2688, 2697, 2707, 2712, 2718, 2731, 2754, 2759, 2760, 2775, 2788, 2793, 2805, + 2811, 2817, 2820, 2832, 2842, 2854, 2890, 2902, 2921, 2923, 2978, 3010, 3012, 3026, 3081, 3083, + 3085, 3097, 3099, 3120, 3136, 3152, 3159, 3188, 3210, 3228, 3234, 3245, 3250, 3256, 3264, 3276, + 3281, 3296, 3349, 3363, 3378, 3392, 3395, 3420, 3440, 3461, 3488, 3529, 3531, 3584, 3588, 3591, + 3600, 3602, 3614, 3616, 3628, 3634, 3650, 3657, 3668, 3683, 3685, 3713, 3716, 3720, 3726, 3729, + 3736, 3753, 3778, 3802, 3805, 3819, 3841, 3845, 3851, 3856, 3880, 3922, 3938, 3970, 3993, 4032, + }; + + const int kmap_size = 4096; + const int nwant = grid_size == 256 ? 2 : 3; + const uint16_t * kgrid = grid_size == 256 ? kgrid_256 : kgrid_512; + uint32_t * kgrid_q3xs; + int * kmap_q3xs; + uint16_t * kneighbors_q3xs; + + //printf("================================================================= %s(grid_size = %d)\n", __func__, grid_size); + uint32_t * the_grid = (uint32_t *)malloc(grid_size*sizeof(uint32_t)); + for (int k = 0; k < grid_size; ++k) { + int8_t * pos = (int8_t *)(the_grid + k); + for (int i = 0; i < 4; ++i) { + int l = (kgrid[k] >> 3*i) & 0x7; + pos[i] = 2*l + 1; + } + } + kgrid_q3xs = the_grid; + iq3_data[gindex].grid = the_grid; + kmap_q3xs = (int *)malloc(kmap_size*sizeof(int)); + iq3_data[gindex].map = kmap_q3xs; + for (int i = 0; i < kmap_size; ++i) kmap_q3xs[i] = -1; + uint32_t aux32; + uint8_t * aux8 = (uint8_t *)&aux32; + for (int i = 0; i < grid_size; ++i) { + aux32 = kgrid_q3xs[i]; + uint16_t index = 0; + for (int k=0; k<4; ++k) { + uint16_t q = (aux8[k] - 1)/2; + index |= (q << 3*k); + } + kmap_q3xs[index] = i; + } + int8_t pos[4]; + int * dist2 = (int *)malloc(2*grid_size*sizeof(int)); + int num_neighbors = 0, num_not_in_map = 0; + for (int i = 0; i < kmap_size; ++i) { + if (kmap_q3xs[i] >= 0) continue; + ++num_not_in_map; + for (int k = 0; k < 4; ++k) { + int l = (i >> 3*k) & 0x7; + pos[k] = 2*l + 1; + } + for (int j = 0; j < grid_size; ++j) { + const int8_t * pg = (const int8_t *)(kgrid_q3xs + j); + int d2 = 0; + for (int k = 0; k < 4; ++k) d2 += (pg[k] - pos[k])*(pg[k] - pos[k]); + dist2[2*j+0] = d2; + dist2[2*j+1] = j; + } + qsort(dist2, grid_size, 2*sizeof(int), iq3_compare_func); + int n = 0; int d2 = dist2[0]; + int nhave = 1; + for (int j = 0; j < grid_size; ++j) { + if (dist2[2*j] > d2) { + if (nhave == nwant) break; + d2 = dist2[2*j]; + ++nhave; + } + ++n; + } + num_neighbors += n; + } + //printf("%s: %d neighbours in total\n", __func__, num_neighbors); + kneighbors_q3xs = (uint16_t *)malloc((num_neighbors + num_not_in_map)*sizeof(uint16_t)); + iq3_data[gindex].neighbours = kneighbors_q3xs; + int counter = 0; + for (int i = 0; i < kmap_size; ++i) { + if (kmap_q3xs[i] >= 0) continue; + for (int k = 0; k < 4; ++k) { + int l = (i >> 3*k) & 0x7; + pos[k] = 2*l + 1; + } + for (int j = 0; j < grid_size; ++j) { + const int8_t * pg = (const int8_t *)(kgrid_q3xs + j); + int d2 = 0; + for (int k = 0; k < 4; ++k) d2 += (pg[k] - pos[k])*(pg[k] - pos[k]); + dist2[2*j+0] = d2; + dist2[2*j+1] = j; + } + qsort(dist2, grid_size, 2*sizeof(int), iq3_compare_func); + kmap_q3xs[i] = -(counter + 1); + int d2 = dist2[0]; + uint16_t * start = &kneighbors_q3xs[counter++]; + int n = 0, nhave = 1; + for (int j = 0; j < grid_size; ++j) { + if (dist2[2*j] > d2) { + if (nhave == nwant) break; + d2 = dist2[2*j]; + ++nhave; + } + kneighbors_q3xs[counter++] = dist2[2*j+1]; + ++n; + } + *start = n; + } + free(dist2); +} + +void iq3xs_free_impl(int grid_size) { + GGML_ASSERT(grid_size == 256 || grid_size == 512); + const int gindex = iq3_data_index(grid_size); + if (iq3_data[gindex].grid) { + free(iq3_data[gindex].grid); iq3_data[gindex].grid = NULL; + free(iq3_data[gindex].map); iq3_data[gindex].map = NULL; + free(iq3_data[gindex].neighbours); iq3_data[gindex].neighbours = NULL; + } +} + +static int iq3_find_best_neighbour(const uint16_t * restrict neighbours, const uint32_t * restrict grid, + const float * restrict xval, const float * restrict weight, float scale, int8_t * restrict L) { + int num_neighbors = neighbours[0]; + GGML_ASSERT(num_neighbors > 0); + float best_d2 = FLT_MAX; + int grid_index = -1; + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float d2 = 0; + for (int i = 0; i < 4; ++i) { + float q = pg[i]; + float diff = scale*q - xval[i]; + d2 += weight[i]*diff*diff; + } + if (d2 < best_d2) { + best_d2 = d2; grid_index = neighbours[j]; + } + } + GGML_ASSERT(grid_index >= 0); + const int8_t * pg = (const int8_t *)(grid + grid_index); + for (int i = 0; i < 4; ++i) L[i] = (pg[i] - 1)/2; + return grid_index; +} + +static void quantize_row_iq3_xxs_impl(int grid_size, const float * restrict x, void * restrict vy, int64_t n, + const float * restrict quant_weights) { + + const int gindex = iq3_data_index(grid_size); + + const uint32_t * kgrid_q3xs = iq3_data[gindex].grid; + const int * kmap_q3xs = iq3_data[gindex].map; + const uint16_t * kneighbors_q3xs = iq3_data[gindex].neighbours; + + //GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kgrid_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kmap_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + const int kMaxQ = 8; + + const int64_t nbl = n/QK_K; + + ggml_fp16_t * dh; + uint8_t * qs; + int block_size; + if (grid_size == 256) { + block_iq3_xxs * y = vy; + dh = &y->d; + qs = y->qs; + block_size = sizeof(block_iq3_xxs); + } else { + block_iq3_s * y = vy; + dh = &y->d; + qs = y->qs; + block_size = sizeof(block_iq3_s); + } + int quant_size = block_size - sizeof(ggml_fp16_t); + + float scales[QK_K/32]; + float weight[32]; + float xval[32]; + int8_t L[32]; + int8_t Laux[32]; + float waux[32]; + bool is_on_grid[8]; + bool is_on_grid_aux[8]; + uint8_t block_signs[8]; + uint8_t q3[3*(QK_K/8)+QK_K/32]; + uint32_t * scales_and_signs = (uint32_t *)(q3 + QK_K/4); + uint8_t * qh = q3 + 3*(QK_K/8); + + for (int ibl = 0; ibl < nbl; ++ibl) { + + dh[0] = GGML_FP32_TO_FP16(0.f); + memset(q3, 0, 3*QK_K/8+QK_K/32); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = 2*sumx2/QK_K; + + for (int ib = 0; ib < QK_K/32; ++ib) { + const float * xb = xbl + 32*ib; + if (quant_weights) { + const float * qw = quant_weights + QK_K*ibl + 32*ib; + for (int i = 0; i < 32; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + } else { + for (int i = 0; i < 32; ++i) weight[i] = xb[i]*xb[i]; + } + for (int i = 0; i < 32; ++i) waux[i] = sqrtf(weight[i]); + for (int k = 0; k < 4; ++k) { + int nflip = 0; + uint8_t s = 0; + for (int i = 0; i < 8; ++i) { + if (xb[8*k + i] >= 0) xval[8*k + i] = xb[8*k + i]; + else { + xval[8*k + i] = -xb[8*k + i]; ++nflip; s |= (1 << i); + } + } + if (nflip%2) { + int imin = 0; float min = weight[8*k+imin]*xb[8*k+imin]*xb[8*k+imin]; + for (int i = 1; i < 8; ++i) { + float ax = weight[8*k+i]*xb[8*k+i]*xb[8*k+i]; + if (ax < min) { + min = ax; imin = i; + } + } + xval[8*k+imin] = -xval[8*k+imin]; + s ^= (1 << imin); + } + block_signs[k] = s & 127; + } + float max = xval[0]; + for (int i = 1; i < 32; ++i) max = MAX(max, xval[i]); + if (!max) { + scales[ib] = 0; + memset(L, 0, 32); + continue; + } + float best = 0; + float scale = max/(2*kMaxQ-1); + for (int is = -15; is <= 15; ++is) { + float id = (2*kMaxQ-1+is*0.2f)/max; + float this_scale = 1/id; + for (int k = 0; k < 8; ++k) { + for (int i = 0; i < 4; ++i) { + int l = nearest_int(0.5f*(id*xval[4*k+i]-1)); + Laux[4*k+i] = MAX(0, MIN(kMaxQ-1, l)); + } + uint16_t u = 0; + for (int i = 0; i < 4; ++i) u |= (Laux[4*k+i] << 3*i); + int grid_index = kmap_q3xs[u]; + is_on_grid_aux[k] = true; + if (grid_index < 0) { + is_on_grid_aux[k] = false; + const uint16_t * neighbours = kneighbors_q3xs - kmap_q3xs[u] - 1; + grid_index = iq3_find_best_neighbour(neighbours, kgrid_q3xs, xval + 4*k, waux + 4*k, this_scale, Laux + 4*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 32; ++i) { + float w = weight[i]; + float q = 2*Laux[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + scale = sumqx/sumq2; best = scale*sumqx; + for (int i = 0; i < 32; ++i) L[i] = Laux[i]; + for (int k = 0; k < 8; ++k) is_on_grid[k] = is_on_grid_aux[k]; + } + } + int n_not_ongrid = 0; + for (int k = 0; k < 8; ++k) if (!is_on_grid[k]) ++n_not_ongrid; + if (n_not_ongrid > 0 && scale > 0) { + float id = 1/scale; + for (int k = 0; k < 8; ++k) { + if (is_on_grid[k]) continue; + uint16_t u = 0; + for (int i = 0; i < 4; ++i) { + int l = nearest_int(0.5f*(id*xval[4*k+i]-1)); + l = MAX(0, MIN(kMaxQ-1, l)); + u |= (l << 3*i); + } + int grid_index = kmap_q3xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q3xs - kmap_q3xs[u] - 1; + grid_index = iq3_find_best_neighbour(neighbours, kgrid_q3xs, xval + 4*k, waux + 4*k, scale, L + 4*k); + } + const int8_t * pg = (const int8_t *)(kgrid_q3xs + grid_index); + for (int i = 0; i < 4; ++i) L[4*k+i] = (pg[i] - 1)/2; + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 32; ++i) { + float w = weight[i]; + float q = 2*L[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0) scale = sumqx/sumq2; + } + if (scale < 0) { + // This should never happen, but just in case, flip scale so that it is positive (we use uint's to encode the scale) + // and correspondingly flip quant signs. + scale = -scale; + for (int k = 0; k < 4; ++k) block_signs[k] = (~block_signs[k]) & 127; + } + for (int k = 0; k < 8; ++k) { + uint16_t u = 0; + for (int i = 0; i < 4; ++i) u |= (L[4*k+i] << 3*i); + int grid_index = kmap_q3xs[u]; + if (grid_index < 0) { + printf("Oops: found point %u not on grid:", u); + for (int i = 0; i < 4; ++i) printf(" %d", L[4*k+i]); + printf("\n"); + GGML_ASSERT(false); + } + if (grid_size == 256) { + q3[8*ib+k] = grid_index; + } else { + q3[8*ib+k] = grid_index & 255; + qh[ib] |= ((grid_index >> 8) << k); + } + + } + scales_and_signs[ib] = block_signs[0] | (block_signs[1] << 7) | (block_signs[2] << 14) | (block_signs[3] << 21); + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + memset(qs, 0, quant_size); + dh += block_size/sizeof(ggml_fp16_t); + qs += block_size; + continue; + } + + float d = max_scale/31; + dh[0] = GGML_FP32_TO_FP16(d * 1.0125f); // small improvement via this fudge factor + float id = 1/d; + for (int ib = 0; ib < QK_K/32; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib]-1)); + l = MAX(0, MIN(15, l)); + scales_and_signs[ib] |= ((uint32_t)l << 28); + } + memcpy(qs, q3, quant_size); + + dh += block_size/sizeof(ggml_fp16_t); + qs += block_size; + + } +} + +size_t quantize_iq3_xxs(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq3_xxs_impl(256, src, qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += nblock*sizeof(block_iq3_xxs); + } + return nrow * nblock * sizeof(block_iq3_xxs); +} + +void quantize_row_iq3_xxs(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_iq3_xxs * restrict y = vy; + quantize_row_iq3_xxs_reference(x, y, k); +} + +void quantize_row_iq3_xxs_reference(const float * restrict x, block_iq3_xxs * restrict y, int64_t k) { + assert(k % QK_K == 0); + quantize_row_iq3_xxs_impl(256, x, y, k, NULL); +} + +static void quantize_row_iq3_s_impl(int block_size, const float * restrict x, void * restrict vy, int n, + const float * restrict quant_weights, + float * scales, + float * weight, + float * xval, + int8_t * L, + int8_t * Laux, + float * waux, + bool * is_on_grid, + bool * is_on_grid_aux, + uint8_t * block_signs) { + + const int gindex = iq3_data_index(512); + + const uint32_t * kgrid_q3xs = iq3_data[gindex].grid; + const int * kmap_q3xs = iq3_data[gindex].map; + const uint16_t * kneighbors_q3xs = iq3_data[gindex].neighbours; + + //GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kgrid_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kmap_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q3xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + const int kMaxQ = 8; + + const int64_t nbl = n/QK_K; + + block_iq3_s * y = vy; + + const int bs4 = block_size/4; + const int bs8 = block_size/8; + + for (int ibl = 0; ibl < nbl; ++ibl) { + + memset(&y[ibl], 0, sizeof(block_iq3_s)); + y[ibl].d = GGML_FP32_TO_FP16(0.f); + + uint8_t * qs = y[ibl].qs; + uint8_t * qh = y[ibl].qh; + uint8_t * signs = y[ibl].signs; + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = 2*sumx2/QK_K; + + for (int ib = 0; ib < QK_K/block_size; ++ib) { + const float * xb = xbl + block_size*ib; + if (quant_weights) { + const float * qw = quant_weights + QK_K*ibl + block_size*ib; + for (int i = 0; i < block_size; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + } else { + for (int i = 0; i < block_size; ++i) weight[i] = xb[i]*xb[i]; + } + for (int i = 0; i < block_size; ++i) waux[i] = sqrtf(weight[i]); + for (int k = 0; k < bs8; ++k) { + uint8_t s = 0; + for (int i = 0; i < 8; ++i) { + if (xb[8*k + i] >= 0) xval[8*k + i] = xb[8*k + i]; + else { + xval[8*k + i] = -xb[8*k + i]; s |= (1 << i); + } + } + block_signs[k] = s; + } + float max = xval[0]; + for (int i = 1; i < block_size; ++i) max = MAX(max, xval[i]); + if (!max) { + scales[ib] = 0; + continue; + } + float best = 0; + float scale = max/(2*kMaxQ-1); + for (int k = 0; k < bs4; ++k) is_on_grid[k] = false; + for (int is = -9; is <= 9; ++is) { + float id = (2*kMaxQ-1+is*0.2f)/max; + float this_scale = 1/id; + for (int k = 0; k < bs4; ++k) { + for (int i = 0; i < 4; ++i) { + int l = nearest_int(0.5f*(id*xval[4*k+i]-1)); + Laux[4*k+i] = MAX(0, MIN(kMaxQ-1, l)); + } + uint16_t u = 0; + for (int i = 0; i < 4; ++i) u |= (Laux[4*k+i] << 3*i); + int grid_index = kmap_q3xs[u]; + is_on_grid_aux[k] = true; + if (grid_index < 0) { + is_on_grid_aux[k] = false; + const uint16_t * neighbours = kneighbors_q3xs - kmap_q3xs[u] - 1; + grid_index = iq3_find_best_neighbour(neighbours, kgrid_q3xs, xval + 4*k, waux + 4*k, this_scale, Laux + 4*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < block_size; ++i) { + float w = weight[i]; + float q = 2*Laux[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + scale = sumqx/sumq2; best = scale*sumqx; + for (int i = 0; i < block_size; ++i) L[i] = Laux[i]; + for (int k = 0; k < bs4; ++k) is_on_grid[k] = is_on_grid_aux[k]; + } + } + int n_not_ongrid = 0; + for (int k = 0; k < bs4; ++k) if (!is_on_grid[k]) ++n_not_ongrid; + if (n_not_ongrid > 0 && scale > 0) { + float id = 1/scale; + for (int k = 0; k < bs4; ++k) { + //if (is_on_grid[k]) continue; + uint16_t u = 0; + for (int i = 0; i < 4; ++i) { + int l = nearest_int(0.5f*(id*xval[4*k+i]-1)); + l = MAX(0, MIN(kMaxQ-1, l)); + u |= (l << 3*i); + } + int grid_index = kmap_q3xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q3xs - kmap_q3xs[u] - 1; + grid_index = iq3_find_best_neighbour(neighbours, kgrid_q3xs, xval + 4*k, waux + 4*k, scale, L + 4*k); + } + const int8_t * pg = (const int8_t *)(kgrid_q3xs + grid_index); + for (int i = 0; i < 4; ++i) L[4*k+i] = (pg[i] - 1)/2; + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < block_size; ++i) { + float w = weight[i]; + float q = 2*L[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0) scale = sumqx/sumq2; + } + if (scale < 0) { + // This should never happen, but just in case, flip scale so that it is positive (we use uint's to encode the scale) + // and correspondingly flip quant signs. + scale = -scale; + for (int k = 0; k < bs8; ++k) block_signs[k] = ~block_signs[k]; + } + for (int k = 0; k < bs4; ++k) { + uint16_t u = 0; + for (int i = 0; i < 4; ++i) u |= (L[4*k+i] << 3*i); + int grid_index = kmap_q3xs[u]; + if (grid_index < 0) { + printf("Oops: found point %u not on grid:", u); + for (int i = 0; i < 4; ++i) printf(" %d", L[4*k+i]); + printf("\n"); + GGML_ASSERT(false); + } + qs[k] = grid_index & 255; + qh[(ib*bs4+k)/8] |= ((grid_index >> 8) << ((ib*bs4+k)%8)); + } + qs += bs4; + for (int k = 0; k < bs8; ++k) signs[k] = block_signs[k]; + signs += bs8; + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + continue; + } + + float d = max_scale/31; + y[ibl].d = GGML_FP32_TO_FP16(d * 1.033f); + float id = 1/d; + for (int ib = 0; ib < QK_K/block_size; ib += 2) { + int l1 = nearest_int(0.5f*(id*scales[ib+0]-1)); + l1 = MAX(0, MIN(15, l1)); + int l2 = nearest_int(0.5f*(id*scales[ib+1]-1)); + l2 = MAX(0, MIN(15, l2)); + y[ibl].scales[ib/2] = l1 | (l2 << 4); + } + + } +} + +#define IQ3S_BLOCK_SIZE 32 +size_t quantize_iq3_s(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + float scales[QK_K/IQ3S_BLOCK_SIZE]; + float weight[IQ3S_BLOCK_SIZE]; + float xval[IQ3S_BLOCK_SIZE]; + int8_t L[IQ3S_BLOCK_SIZE]; + int8_t Laux[IQ3S_BLOCK_SIZE]; + float waux[IQ3S_BLOCK_SIZE]; + bool is_on_grid[IQ3S_BLOCK_SIZE/4]; + bool is_on_grid_aux[IQ3S_BLOCK_SIZE/4]; + uint8_t block_signs[IQ3S_BLOCK_SIZE/8]; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq3_s_impl(IQ3S_BLOCK_SIZE, src, qrow, n_per_row, quant_weights, + scales, weight, xval, L, Laux, waux, is_on_grid, is_on_grid_aux, block_signs); + src += n_per_row; + qrow += nblock*sizeof(block_iq3_s); + } + return nrow * nblock * sizeof(block_iq3_s); +} + +void quantize_row_iq3_s(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_iq3_s * restrict y = vy; + quantize_row_iq3_s_reference(x, y, k); +} + +void quantize_row_iq3_s_reference(const float * restrict x, block_iq3_s * restrict y, int64_t k) { + assert(k % QK_K == 0); + quantize_iq3_s(x, y, 1, k, NULL); +} + + +// =================================== 1.5 bpw =================================================== + +static int iq1_find_best_neighbour(const uint16_t * restrict neighbours, const uint64_t * restrict grid, + const float * restrict xval, const float * restrict weight, float * scale, int8_t * restrict L, int ngrid) { + int num_neighbors = neighbours[0]; + GGML_ASSERT(num_neighbors > 0); + float best_score = 0; + int grid_index = -1; + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 8; ++i) { + float q = (pg[i] - 3)/2; + float w = weight[i]; + sumqx += w*q*xval[i]; + sumq2 += w*q*q; + } + if (sumqx > 0 && sumq2 > 0 && sumqx*sumqx > best_score*sumq2) { + *scale = sumqx/sumq2; best_score = *scale * sumqx; + grid_index = neighbours[j]; + } + } + if (grid_index < 0) { + for (int i = 0; i < ngrid; ++i) { + const int8_t * grid_i = (const int8_t *)(grid + i); + float sumqx = 0, sumq2 = 0; + for (int j = 0; j < 8; ++j) { + float w = weight[j]; + float q = (grid_i[j] - 3)/2; + sumqx += w*q*xval[j]; + sumq2 += w*q*q; + } + if (sumqx > 0 && sumq2 > 0 && sumqx*sumqx > best_score*sumq2) { + *scale = sumqx/sumq2; best_score = *scale*sumqx; + grid_index = i; + } + } + } + if (grid_index < 0) { + printf("Oops, did not find grid point\n"); + printf("Have %d neighbours\n", num_neighbors); + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 8; ++i) { + float q = (pg[i] - 3)/2; + float w = weight[i]; + sumqx += w*q*xval[i]; + sumq2 += w*q*q; + } + printf(" neighbour %d: sumqx = %g sumq2 = %g\n", j, (double)sumqx, (double)sumq2); + } + } + GGML_ASSERT(grid_index >= 0); + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + *scale *= 1.05f; // This is a fudge factor. Don't ask me why it improves the result. + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + const int8_t * pg = (const int8_t *)(grid + grid_index); + for (int i = 0; i < 8; ++i) L[i] = (pg[i] - 1)/2; + return grid_index; +} + +static int iq1_find_best_neighbour2(const uint16_t * restrict neighbours, const uint64_t * restrict grid, + const float * restrict xval, const float * restrict weight, float scale, const float * restrict xg, int8_t * restrict L, int ngrid) { + int num_neighbors = neighbours[0]; + GGML_ASSERT(num_neighbors > 0); + float best_score = FLT_MAX; + int grid_index = -1; + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float d2 = 0; + for (int i = 0; i < 8; ++i) { + float q = xg[(pg[i] - 1)/2]; + float w = weight[i]; + float diff = scale*q - xval[i]; + d2 += w*diff*diff; + } + if (d2 < best_score) { + best_score = d2; + grid_index = neighbours[j]; + } + } + if (grid_index < 0) { + for (int i = 0; i < ngrid; ++i) { + const int8_t * grid_i = (const int8_t *)(grid + i); + float d2 = 0; + for (int j = 0; j < 8; ++j) { + float w = weight[j]; + float q = xg[(grid_i[j] - 1)/2]; + float diff = scale*q - xval[i]; + d2 += w*diff*diff; + } + if (d2 < best_score) { + best_score = d2; + grid_index = i; + } + } + } + if (grid_index < 0) { + printf("Oops, did not find grid point\n"); + printf("Have %d neighbours\n", num_neighbors); + for (int j = 1; j <= num_neighbors; ++j) { + const int8_t * pg = (const int8_t *)(grid + neighbours[j]); + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 8; ++i) { + float q = xg[(pg[i] - 1)/2]; + float w = weight[i]; + sumqx += w*q*xval[i]; + sumq2 += w*q*q; + } + printf(" neighbour %d: sumqx = %g sumq2 = %g\n", j, (double)sumqx, (double)sumq2); + } + } + GGML_ASSERT(grid_index >= 0); + const int8_t * pg = (const int8_t *)(grid + grid_index); + for (int i = 0; i < 8; ++i) L[i] = (pg[i] - 1)/2; + return grid_index; +} + +static int iq1_sort_helper(const void * left, const void * right) { + const float * l = left; + const float * r = right; + return *l < *r ? -1 : *l > *r ? 1 : 0; +} + +#define IQ1S_BLOCK_SIZE 32 +#define IQ1M_BLOCK_SIZE 16 +static void quantize_row_iq1_s_impl(const float * restrict x, void * restrict vy, int64_t n, const float * restrict quant_weights, + float * scales, + float * weight, + float * sumx, + float * sumw, + float * pairs, + int8_t * L, + uint16_t * index, + int8_t * shifts) { + + const int gindex = iq2_data_index(GGML_TYPE_IQ1_S); + + const uint64_t * kgrid_q2xs = iq2_data[gindex].grid; + const int * kmap_q2xs = iq2_data[gindex].map; + const uint16_t * kneighbors_q2xs = iq2_data[gindex].neighbours; + + GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kgrid_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kmap_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + block_iq1_s * y = vy; + + const int64_t nbl = n/QK_K; + + const int block_size = IQ1S_BLOCK_SIZE; + + const float x_p[3] = {-1 + IQ1S_DELTA, IQ1S_DELTA, 1 + IQ1S_DELTA}; + const float x_m[3] = {-1 - IQ1S_DELTA, -IQ1S_DELTA, 1 - IQ1S_DELTA}; + + + int * idx = (int *)(pairs + 1); + + for (int ibl = 0; ibl < nbl; ++ibl) { + + y[ibl].d = GGML_FP32_TO_FP16(0.f); + memset(y[ibl].qs, 0, QK_K/8); + memset(y[ibl].qh, 0, QK_K/16); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = 2*sumx2/QK_K; + + for (int ib = 0; ib < QK_K/block_size; ++ib) { + const float * xb = xbl + block_size*ib; + const float * qw = quant_weights + QK_K*ibl + block_size*ib; + for (int i = 0; i < block_size; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + float max = fabsf(xb[0]); + for (int i = 1; i < block_size; ++i) max = MAX(max, fabsf(xb[i])); + if (!max) { + scales[ib] = 0; + memset(L, 1, block_size); + continue; + } + // Here we solve exactly the sum of squared difference (SSD) weighted minimization problem. + // With just 3 allowed quant values (-1, 0, 1), we can search exhaustively for the two + // boundaries that split the weights xb[i] into 3 groups. To do so, we sort the weights + // in ascending order, compute Si = sum[weight[j] xb[j], j = 0...i] and + // Wi = sum[weight[j], j = 0...i], and use these to quckly get get the optimum scale + // for each possible and score for each split. + for (int j = 0; j < block_size; ++j) { + pairs[2*j] = xb[j]; + idx[2*j] = j; + } + qsort(pairs, block_size, 2*sizeof(float), iq1_sort_helper); + { + sumx[0] = sumw[0] = 0; + for (int j = 0; j < block_size; ++j) { + int i = idx[2*j]; + sumx[j+1] = sumx[j] + weight[i]*xb[i]; + sumw[j+1] = sumw[j] + weight[i]; + } + } + float best_score = 0, scale = max; + int besti1 = -1, besti2 = -1, best_shift = 0; + for (int i1 = 0; i1 <= block_size; ++i1) { + for (int i2 = i1; i2 <= block_size; ++i2) { + float sumqx = (sumx[i1] - sumx[0])*x_p[0] + (sumx[i2] - sumx[i1])*x_p[1] + (sumx[block_size] - sumx[i2])*x_p[2]; + float sumq2 = (sumw[i1] - sumw[0])*x_p[0]*x_p[0] + (sumw[i2] - sumw[i1])*x_p[1]*x_p[1] + (sumw[block_size] - sumw[i2])*x_p[2]*x_p[2]; + if (sumq2 > 0 && sumqx*sumqx > best_score*sumq2) { + scale = sumqx/sumq2; best_score = scale*sumqx; + besti1 = i1; besti2 = i2; best_shift = 1; + } + sumqx = (sumx[i1] - sumx[0])*x_m[0] + (sumx[i2] - sumx[i1])*x_m[1] + (sumx[block_size] - sumx[i2])*x_m[2]; + sumq2 = (sumw[i1] - sumw[0])*x_m[0]*x_m[0] + (sumw[i2] - sumw[i1])*x_m[1]*x_m[1] + (sumw[block_size] - sumw[i2])*x_m[2]*x_m[2]; + if (sumq2 > 0 && sumqx*sumqx > best_score*sumq2) { + scale = sumqx/sumq2; best_score = scale*sumqx; + besti1 = i1; besti2 = i2; best_shift = -1; + } + } + } + GGML_ASSERT(besti1 >= 0 && besti2 >= 0 && best_shift != 0); + for (int j = 0; j < besti1; ++j) L[idx[2*j]] = 0; + for (int j = besti1; j < besti2; ++j) L[idx[2*j]] = 1; + for (int j = besti2; j < block_size; ++j) L[idx[2*j]] = 2; + if (scale < 0) { + for (int j = 0; j < block_size; ++j) L[j] = 2 - L[j]; + scale = -scale; best_shift = -best_shift; + } + bool all_on_grid = true; + const float * xx = best_shift == 1 ? x_p : x_m; + for (int k = 0; k < block_size/8; ++k) { + uint16_t u = 0; + for (int j = 0; j < 8; ++j) u |= (L[8*k+j] << 2*j); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + all_on_grid = false; + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq1_find_best_neighbour2(neighbours, kgrid_q2xs, xb + 8*k, weight + 8*k, scale, xx, L + 8*k, NGRID_IQ1S); + GGML_ASSERT(grid_index >= 0); + } + index[k] = grid_index; + } + if (!all_on_grid) { + float sumqx = 0, sumq2 = 0; + for (int k = 0; k < block_size/8; ++k) { + const int8_t * pg = (const int8_t *)(kgrid_q2xs + index[k]); + for (int j = 0; j < 8; ++j) { + float w = weight[8*k + j]; + float q = xx[(pg[j] - 1)/2]; + sumqx += w*q*xb[8*k+j]; + sumq2 += w*q*q; + } + } + if (sumqx > 0 && sumq2 > 0) scale = sumqx/sumq2; + } + uint16_t h = 0; + for (int k = 0; k < block_size/8; ++k) { + y[ibl].qs[(block_size/8)*ib + k] = index[k] & 255; + h |= (index[k] >> 8) << 3*k; + } + y[ibl].qh[ib] = h; + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + shifts[ib] = best_shift; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + continue; + } + + float d = max_scale/15; + y[ibl].d = GGML_FP32_TO_FP16(d*1.125f); // 1.125f is another fudge factor. Don't ask me why it is needed. + float id = 1/d; + for (int ib = 0; ib < QK_K/block_size; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib]-1)); + l = MAX(0, MIN(7, l)); + if (shifts[ib] == -1) l |= 8; + y[ibl].qh[ib] |= (l << 12); + } + } +} + +size_t quantize_iq1_s(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + float scales[QK_K/IQ1S_BLOCK_SIZE]; + float weight[IQ1S_BLOCK_SIZE]; + int8_t L[IQ1S_BLOCK_SIZE]; + float sumx[IQ1S_BLOCK_SIZE+1]; + float sumw[IQ1S_BLOCK_SIZE+1]; + float pairs[2*IQ1S_BLOCK_SIZE]; + uint16_t index[IQ1S_BLOCK_SIZE/8]; + int8_t shifts[QK_K/IQ1S_BLOCK_SIZE]; + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq1_s_impl(src, qrow, n_per_row, quant_weights, scales, weight, sumx, sumw, pairs, L, index, shifts); + src += n_per_row; + qrow += nblock*sizeof(block_iq1_s); + } + return nrow * nblock * sizeof(block_iq1_s); +} + +static void quantize_row_iq1_m_impl(const float * restrict x, void * restrict vy, int64_t n, const float * restrict quant_weights, + float * scales, + float * weight, + float * pairs, + int8_t * L, + uint16_t * index, + int8_t * shifts) { + + const int gindex = iq2_data_index(GGML_TYPE_IQ1_M); + + const uint64_t * kgrid_q2xs = iq2_data[gindex].grid; + const int * kmap_q2xs = iq2_data[gindex].map; + const uint16_t * kneighbors_q2xs = iq2_data[gindex].neighbours; + + //GGML_ASSERT(quant_weights && "missing quantization weights"); + GGML_ASSERT(kgrid_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kmap_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + block_iq1_m * y = vy; + + const int64_t nbl = n/QK_K; + + const int block_size = IQ1M_BLOCK_SIZE; + + const float x_p[3] = {-1 + IQ1M_DELTA, IQ1M_DELTA, 1 + IQ1M_DELTA}; + const float x_m[3] = {-1 - IQ1M_DELTA, -IQ1M_DELTA, 1 - IQ1M_DELTA}; + const uint8_t masks[4] = {0x00, 0x80, 0x08, 0x88}; + + int * idx = (int *)(pairs + 1); + + float sumqx[4], sumq2[4]; + + iq1m_scale_t s; + const float * xx; + + for (int ibl = 0; ibl < nbl; ++ibl) { + +#if QK_K == 64 + y[ibl].d = GGML_FP32_TO_FP16(0.f); +#endif + memset(y[ibl].qs, 0, QK_K/8); + memset(y[ibl].qh, 0, QK_K/16); + memset(y[ibl].scales, 0, QK_K/32); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = 2*sumx2/QK_K; + + for (int ib = 0; ib < QK_K/block_size; ++ib) { + const float * xb = xbl + block_size*ib; + if (quant_weights) { + const float * qw = quant_weights + QK_K*ibl + block_size*ib; + for (int i = 0; i < block_size; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + } else { + for (int i = 0; i < block_size; ++i) weight[i] = xb[i]*xb[i]; + } + float max = fabsf(xb[0]); + for (int i = 1; i < block_size; ++i) max = MAX(max, fabsf(xb[i])); + if (!max) { + scales[ib] = 0; + memset(L, 1, block_size); + continue; + } + // Here we solve exactly the sum of squared difference (SSD) weighted minimization problem. + // With just 3 allowed quant values (-1, 0, 1), we can search exhaustively for the two + // boundaries that split the weights xb[i] into 3 groups. To do so, we sort the weights + // in ascending order, compute Si = sum[weight[j] xb[j], j = 0...i] and + // Wi = sum[weight[j], j = 0...i], and use these to quckly get get the optimum scale + // for each possible and score for each split. + for (int j = 0; j < block_size; ++j) { + pairs[2*j] = xb[j]; + idx[2*j] = j; + } + qsort(pairs, block_size, 2*sizeof(float), iq1_sort_helper); + float best_score = 0, scale = max; + int besti1 = -1, besti2 = -1, best_k = -1; + // 0: +, + + // 1: +, - + // 2: -, + + // 3: -, - + for (int i1 = 0; i1 <= block_size; ++i1) { + for (int i2 = i1; i2 <= block_size; ++i2) { + memset(sumqx, 0, 4*sizeof(float)); + memset(sumq2, 0, 4*sizeof(float)); + for (int j = 0; j < i1; ++j) { + int i = idx[2*j]; + if (i < block_size/2) { + sumqx[0] += weight[i]*x_p[0]*xb[i]; + sumqx[1] += weight[i]*x_p[0]*xb[i]; + sumqx[2] += weight[i]*x_m[0]*xb[i]; + sumqx[3] += weight[i]*x_m[0]*xb[i]; + sumq2[0] += weight[i]*x_p[0]*x_p[0]; + sumq2[1] += weight[i]*x_p[0]*x_p[0]; + sumq2[2] += weight[i]*x_m[0]*x_m[0]; + sumq2[3] += weight[i]*x_m[0]*x_m[0]; + } else { + sumqx[0] += weight[i]*x_p[0]*xb[i]; + sumqx[2] += weight[i]*x_p[0]*xb[i]; + sumqx[1] += weight[i]*x_m[0]*xb[i]; + sumqx[3] += weight[i]*x_m[0]*xb[i]; + sumq2[0] += weight[i]*x_p[0]*x_p[0]; + sumq2[2] += weight[i]*x_p[0]*x_p[0]; + sumq2[1] += weight[i]*x_m[0]*x_m[0]; + sumq2[3] += weight[i]*x_m[0]*x_m[0]; + } + } + for (int j = i1; j < i2; ++j) { + int i = idx[2*j]; + if (i < block_size/2) { + sumqx[0] += weight[i]*x_p[1]*xb[i]; + sumqx[1] += weight[i]*x_p[1]*xb[i]; + sumqx[2] += weight[i]*x_m[1]*xb[i]; + sumqx[3] += weight[i]*x_m[1]*xb[i]; + sumq2[0] += weight[i]*x_p[1]*x_p[1]; + sumq2[1] += weight[i]*x_p[1]*x_p[1]; + sumq2[2] += weight[i]*x_m[1]*x_m[1]; + sumq2[3] += weight[i]*x_m[1]*x_m[1]; + } else { + sumqx[0] += weight[i]*x_p[1]*xb[i]; + sumqx[2] += weight[i]*x_p[1]*xb[i]; + sumqx[1] += weight[i]*x_m[1]*xb[i]; + sumqx[3] += weight[i]*x_m[1]*xb[i]; + sumq2[0] += weight[i]*x_p[1]*x_p[1]; + sumq2[2] += weight[i]*x_p[1]*x_p[1]; + sumq2[1] += weight[i]*x_m[1]*x_m[1]; + sumq2[3] += weight[i]*x_m[1]*x_m[1]; + } + } + for (int j = i2; j < block_size; ++j) { + int i = idx[2*j]; + if (i < block_size/2) { + sumqx[0] += weight[i]*x_p[2]*xb[i]; + sumqx[1] += weight[i]*x_p[2]*xb[i]; + sumqx[2] += weight[i]*x_m[2]*xb[i]; + sumqx[3] += weight[i]*x_m[2]*xb[i]; + sumq2[0] += weight[i]*x_p[2]*x_p[2]; + sumq2[1] += weight[i]*x_p[2]*x_p[2]; + sumq2[2] += weight[i]*x_m[2]*x_m[2]; + sumq2[3] += weight[i]*x_m[2]*x_m[2]; + } else { + sumqx[0] += weight[i]*x_p[2]*xb[i]; + sumqx[2] += weight[i]*x_p[2]*xb[i]; + sumqx[1] += weight[i]*x_m[2]*xb[i]; + sumqx[3] += weight[i]*x_m[2]*xb[i]; + sumq2[0] += weight[i]*x_p[2]*x_p[2]; + sumq2[2] += weight[i]*x_p[2]*x_p[2]; + sumq2[1] += weight[i]*x_m[2]*x_m[2]; + sumq2[3] += weight[i]*x_m[2]*x_m[2]; + } + } + for (int k = 0; k < 4; ++k) { + if (sumq2[k] > 0 && sumqx[k]*sumqx[k] > best_score*sumq2[k]) { + scale = sumqx[k]/sumq2[k]; best_score = scale*sumqx[k]; + besti1 = i1; besti2 = i2; best_k = k; + } + } + } + } + GGML_ASSERT(besti1 >= 0 && besti2 >= 0 && best_k >= 0); + for (int j = 0; j < besti1; ++j) L[idx[2*j]] = 0; + for (int j = besti1; j < besti2; ++j) L[idx[2*j]] = 1; + for (int j = besti2; j < block_size; ++j) L[idx[2*j]] = 2; + if (scale < 0) { + for (int j = 0; j < block_size; ++j) L[j] = 2 - L[j]; + scale = -scale; + best_k = best_k == 0 ? 3 : best_k == 1 ? 2 : best_k == 2 ? 1 : 0; + } + bool all_on_grid = true; + for (int k = 0; k < block_size/8; ++k) { + if (k == 0) xx = best_k < 2 ? x_p : x_m; + else xx = best_k%2 == 0 ? x_p : x_m; + uint16_t u = 0; + for (int j = 0; j < 8; ++j) u |= (L[8*k+j] << 2*j); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + all_on_grid = false; + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq1_find_best_neighbour2(neighbours, kgrid_q2xs, xb + 8*k, weight + 8*k, scale, xx, L + 8*k, NGRID_IQ1S); + GGML_ASSERT(grid_index >= 0); + } + index[k] = grid_index; + } + if (!all_on_grid) { + float sumqx_f = 0, sumq2_f = 0; + for (int k = 0; k < block_size/8; ++k) { + if (k == 0) xx = best_k < 2 ? x_p : x_m; + else xx = best_k%2 == 0 ? x_p : x_m; + const int8_t * pg = (const int8_t *)(kgrid_q2xs + index[k]); + for (int j = 0; j < 8; ++j) { + float w = weight[8*k + j]; + float q = xx[(pg[j] - 1)/2]; + sumqx_f += w*q*xb[8*k+j]; + sumq2_f += w*q*q; + } + } + if (sumqx_f > 0 && sumq2_f > 0) scale = sumqx_f/sumq2_f; + } + y[ibl].qs[2*ib + 0] = index[0] & 255; + y[ibl].qs[2*ib + 1] = index[1] & 255; + y[ibl].qh[ib] = (index[0] >> 8) | ((index[1] >> 8) << 4); + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + shifts[ib] = best_k; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + continue; + } + + uint16_t * sc = (uint16_t *)y[ibl].scales; +#if QK_K == 64 + float d = max_scale/31; +#else + float d = max_scale/15; +#endif + float id = 1/d; + float sumqx_f = 0, sumq2_f = 0; + for (int ib = 0; ib < QK_K/block_size; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib+0]-1)); +#if QK_K == 64 + l = MAX(0, MIN(15, l)); + sc[ib/4] |= (l << 4*(ib%4)); +#else + l = MAX(0, MIN(7, l)); + sc[ib/4] |= (l << 3*(ib%4)); +#endif + y[ibl].qh[ib] |= masks[shifts[ib]]; + const float * xb = xbl + block_size*ib; + if (quant_weights) { + const float * qw = quant_weights + QK_K*ibl + block_size*ib; + for (int i = 0; i < block_size; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + } else { + for (int i = 0; i < block_size; ++i) weight[i] = xb[i]*xb[i]; + } + for (int k = 0; k < block_size/8; ++k) { + if (k == 0) xx = shifts[ib] < 2 ? x_p : x_m; + else xx = shifts[ib]%2 == 0 ? x_p : x_m; + const int8_t * pg = (const int8_t *)(kgrid_q2xs + y[ibl].qs[2*ib+k] + ((y[ibl].qh[ib] << (8 - 4*k)) & 0x700)); + for (int j = 0; j < 8; ++j) { + float w = weight[8*k + j]; + float q = xx[(pg[j] - 1)/2]*(2*l+1); + sumqx_f += w*q*xb[8*k+j]; + sumq2_f += w*q*q; + } + } + } + if (sumq2_f > 0) d = sumqx_f/sumq2_f; + s.f16 = GGML_FP32_TO_FP16(d*1.1125f); // 1.1125f is another fudge factor. Don't ask me why it is needed. +#if QK_K == 64 + y[ibl].d = s.f16; +#else + sc[0] |= ((s.u16 & 0x000f) << 12); + sc[1] |= ((s.u16 & 0x00f0) << 8); + sc[2] |= ((s.u16 & 0x0f00) << 4); + sc[3] |= ((s.u16 & 0xf000) << 0); +#endif + } +} + +size_t quantize_iq1_m(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + float scales[QK_K/IQ1M_BLOCK_SIZE]; + float weight[IQ1M_BLOCK_SIZE]; + int8_t L[IQ1M_BLOCK_SIZE]; + float pairs[2*IQ1M_BLOCK_SIZE]; + uint16_t index[IQ1M_BLOCK_SIZE/8]; + int8_t shifts[QK_K/IQ1M_BLOCK_SIZE]; + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq1_m_impl(src, qrow, n_per_row, quant_weights, scales, weight, pairs, L, index, shifts); + src += n_per_row; + qrow += nblock*sizeof(block_iq1_m); + } + return nrow * nblock * sizeof(block_iq1_m); +} + +// ============================ 4-bit non-linear quants + +static inline int best_index_int8(int n, const int8_t * val, float x) { + if (x <= val[0]) return 0; + if (x >= val[n-1]) return n-1; + int ml = 0, mu = n-1; + while (mu-ml > 1) { + int mav = (ml+mu)/2; + if (x < val[mav]) mu = mav; else ml = mav; + } + return x - val[mu-1] < val[mu] - x ? mu-1 : mu; +} + +static void quantize_row_iq4_nl_impl(const int super_block_size, const int block_size, const float * restrict x, + ggml_fp16_t * dh, uint8_t * q4, uint16_t * scales_h, uint8_t * scales_l, + float * scales, float * weight, uint8_t * L, + const int8_t * values, + const float * quant_weights, + const int ntry) { + + float sigma2 = 0; + for (int j = 0; j < super_block_size; ++j) sigma2 += x[j]*x[j]; + sigma2 *= 2.f/super_block_size; + + memset(q4, 0, super_block_size/2); + dh[0] = GGML_FP32_TO_FP16(0.f); + + float max_scale = 0, amax_scale = 0; + for (int ib = 0; ib < super_block_size/block_size; ++ib) { + const float * xb = x + ib*block_size; + uint8_t * Lb = L + ib*block_size; + if (quant_weights) { + const float * qw = quant_weights + ib*block_size; + for (int j = 0; j < block_size; ++j) weight[j] = qw[j] * sqrtf(sigma2 + xb[j]*xb[j]); + } else { + for (int j = 0; j < block_size; ++j) weight[j] = xb[j]*xb[j]; + } + float amax = 0, max = 0; + for (int j = 0; j < block_size; ++j) { + float ax = fabsf(xb[j]); + if (ax > amax) { + amax = ax; max = xb[j]; + } + } + if (!amax) { + scales[ib] = 0; + continue; + } + float d = ntry > 0 ? -max/values[0] : max/values[0]; + float id = 1/d; + float sumqx = 0, sumq2 = 0; + for (int j = 0; j < block_size; ++j) { + float al = id*xb[j]; + int l = best_index_int8(16, values, al); + Lb[j] = l; + float q = values[l]; + float w = weight[j]; + sumqx += w*q*xb[j]; + sumq2 += w*q*q; + } + d = sumqx/sumq2; + float best = d*sumqx; + for (int itry = -ntry; itry <= ntry; ++itry) { + id = (itry + values[0])/max; + sumqx = sumq2 = 0; + for (int j = 0; j < block_size; ++j) { + float al = id*xb[j]; + int l = best_index_int8(16, values, al); + float q = values[l]; + float w = weight[j]; + sumqx += w*q*xb[j]; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + d = sumqx/sumq2; best = d * sumqx; + } + } + scales[ib] = d; + float abs_d = fabsf(d); + if (abs_d > amax_scale) { + amax_scale = abs_d; max_scale = d; + } + } + + if (super_block_size/block_size > 1) { + int nb = super_block_size/block_size; + memset(scales_h, 0, ((nb+7)/8)*sizeof(uint16_t)); + float d = -max_scale/32; + dh[0] = GGML_FP32_TO_FP16(d); + float id = d ? 1/d : 0.f; + for (int ib = 0; ib < super_block_size/block_size; ++ib) { + int l = nearest_int(id*scales[ib]); + l = MAX(-32, MIN(31, l)); + float dl = d * l; + float idl = dl ? 1/dl : 0.f; + uint8_t * Lb = L + ib*block_size; + const float * xb = x + ib*block_size; + for (int j = 0; j < block_size; ++j) { + Lb[j] = best_index_int8(16, values, idl*xb[j]); + } + l += 32; + uint8_t l_l = l & 0xf; + uint8_t l_h = l >> 4; + if (ib%2 == 0) scales_l[ib/2] = l_l; + else scales_l[ib/2] |= (l_l << 4); + scales_h[ib/8] |= (l_h << 2*(ib%8)); + } + } else { + dh[0] = GGML_FP32_TO_FP16(scales[0]); + if (ntry > 0) { + float id = scales[0] ? 1/scales[0] : 0; + for (int j = 0; j < super_block_size; ++j) { + L[j] = best_index_int8(16, values, id*x[j]); + } + } + } + + for (int i = 0; i < super_block_size/32; ++i) { + for (int j = 0; j < 16; ++j) { + q4[16*i + j] = L[32*i + j] | (L[32*i + 16 + j] << 4); + } + } +} + +size_t quantize_iq4_nl(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK4_NL == 0); + int64_t nblock = n_per_row/QK4_NL; + char * qrow = (char *)dst; + uint8_t L[QK4_NL]; + float weight[QK4_NL]; + uint16_t unused_h; + uint8_t * unused_l = NULL; + float scale; + for (int64_t row = 0; row < nrow; ++row) { + block_iq4_nl * iq4 = (block_iq4_nl *)qrow; + for (int ibl = 0; ibl < nblock; ++ibl) { + const float * qw = quant_weights ? quant_weights + QK4_NL*ibl : NULL; + quantize_row_iq4_nl_impl(QK4_NL, 32, src + QK4_NL*ibl, &iq4[ibl].d, iq4[ibl].qs, &unused_h, unused_l, + &scale, weight, L, kvalues_iq4nl, qw, 7); + } + src += n_per_row; + qrow += nblock*sizeof(block_iq4_nl); + } + return nrow * nblock * sizeof(block_iq4_nl); +} + +void quantize_row_iq4_nl(const float * restrict x, void * restrict vy, int64_t k) { + GGML_ASSERT(k%QK4_NL == 0); + int64_t nblock = k/QK4_NL; + uint8_t L[QK4_NL]; + float weight[QK4_NL]; + uint16_t unused_h; + uint8_t * unused_l = NULL; + float scale; + block_iq4_nl * iq4 = (block_iq4_nl *)vy; + for (int ibl = 0; ibl < nblock; ++ibl) { + quantize_row_iq4_nl_impl(QK4_NL, 32, x + QK4_NL*ibl, &iq4[ibl].d, iq4[ibl].qs, &unused_h, unused_l, + &scale, weight, L, kvalues_iq4nl, NULL, -1); + } +} + +void quantize_row_iq4_nl_reference(const float * restrict x, block_iq4_nl * restrict y, int64_t k) { + assert(k % QK4_NL == 0); + quantize_row_iq4_nl(x, y, k); +} + +size_t quantize_iq4_xs(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { +#if QK_K == 64 + return quantize_iq4_nl(src, dst, nrow, n_per_row, quant_weights); +#else + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + uint8_t L[QK_K]; + float weight[32]; + float scales[QK_K/32]; + for (int64_t row = 0; row < nrow; ++row) { + block_iq4_xs * iq4 = (block_iq4_xs *)qrow; + for (int ibl = 0; ibl < nblock; ++ibl) { + const float * qw = quant_weights ? quant_weights + QK_K*ibl : NULL; + quantize_row_iq4_nl_impl(QK_K, 32, src + QK_K*ibl, &iq4[ibl].d, iq4[ibl].qs, &iq4[ibl].scales_h, iq4[ibl].scales_l, + scales, weight, L, kvalues_iq4nl, qw, 7); + } + src += n_per_row; + qrow += nblock*sizeof(block_iq4_xs); + } + return nrow * nblock * sizeof(block_iq4_xs); +#endif +} + +void quantize_row_iq4_xs(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_iq4_xs * restrict y = vy; + quantize_row_iq4_xs_reference(x, y, k); +} + +void quantize_row_iq4_xs_reference(const float * restrict x, block_iq4_xs * restrict y, int64_t k) { + assert(k % QK_K == 0); + quantize_iq4_xs(x, y, 1, k, NULL); +} + +// =============================== 2.5625 bpw + +static void quantize_row_iq2_s_impl(const float * restrict x, void * restrict vy, int64_t n, const float * restrict quant_weights) { + + const int gindex = iq2_data_index(GGML_TYPE_IQ2_S); + + const uint64_t * kgrid_q2xs = iq2_data[gindex].grid; + const int * kmap_q2xs = iq2_data[gindex].map; + const uint16_t * kneighbors_q2xs = iq2_data[gindex].neighbours; + + GGML_ASSERT(kmap_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kgrid_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(kneighbors_q2xs && "forgot to call ggml_quantize_init()?"); + GGML_ASSERT(n%QK_K == 0); + + const int kMaxQ = 3; + + const int64_t nbl = n/QK_K; + + block_iq2_s * y = vy; + + float scales[QK_K/16]; + float weight[16]; + float xval[16]; + int8_t L[16]; + int8_t Laux[16]; + float waux[16]; + bool is_on_grid[2]; + bool is_on_grid_aux[2]; + uint8_t block_signs[2]; + + for (int ibl = 0; ibl < nbl; ++ibl) { + + memset(&y[ibl], 0, sizeof(block_iq2_s)); + y[ibl].d = GGML_FP32_TO_FP16(0.f); + + float max_scale = 0; + + const float * xbl = x + QK_K*ibl; + float sumx2 = 0; + for (int i = 0; i < QK_K; ++i) sumx2 += xbl[i]*xbl[i]; + float sigma2 = 2*sumx2/QK_K; + + for (int ib = 0; ib < QK_K/16; ++ib) { + const float * xb = xbl + 16*ib; + if (quant_weights) { + const float * qw = quant_weights + QK_K*ibl + 16*ib; + for (int i = 0; i < 16; ++i) weight[i] = qw[i] * sqrtf(sigma2 + xb[i]*xb[i]); + } else { + for (int i = 0; i < 16; ++i) weight[i] = 0.25f*sigma2 + xb[i]*xb[i]; + } + for (int i = 0; i < 16; ++i) waux[i] = sqrtf(weight[i]); + for (int k = 0; k < 2; ++k) { + uint8_t s = 0; + for (int i = 0; i < 8; ++i) { + if (xb[8*k + i] >= 0) xval[8*k + i] = xb[8*k + i]; + else { + xval[8*k + i] = -xb[8*k + i]; s |= (1 << i); + } + } + block_signs[k] = s; + } + float max = xval[0]; + for (int i = 1; i < 16; ++i) max = MAX(max, xval[i]); + if (!max) { + scales[ib] = 0; + continue; + } + float best = 0; + float scale = max/(2*kMaxQ-1); + is_on_grid[0] = is_on_grid[1] = true; + for (int is = -9; is <= 9; ++is) { + float id = (2*kMaxQ-1+is*0.1f)/max; + float this_scale = 1/id; + for (int k = 0; k < 2; ++k) { + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + Laux[8*k+i] = MAX(0, MIN(kMaxQ-1, l)); + } + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (Laux[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + is_on_grid_aux[k] = true; + if (grid_index < 0) { + is_on_grid_aux[k] = false; + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, this_scale, Laux + 8*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 16; ++i) { + float w = weight[i]; + float q = 2*Laux[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0 && sumqx*sumqx > best*sumq2) { + scale = sumqx/sumq2; best = scale*sumqx; + for (int i = 0; i < 16; ++i) L[i] = Laux[i]; + for (int k = 0; k < 2; ++k) is_on_grid[k] = is_on_grid_aux[k]; + } + } + int n_not_ongrid = 0; + for (int k = 0; k < 2; ++k) if (!is_on_grid[k]) ++n_not_ongrid; + if (n_not_ongrid > 0 && scale > 0) { + float id = 1/scale; + for (int k = 0; k < 2; ++k) { + if (is_on_grid[k]) continue; + uint16_t u = 0; + for (int i = 0; i < 8; ++i) { + int l = nearest_int(0.5f*(id*xval[8*k+i]-1)); + l = MAX(0, MIN(kMaxQ-1, l)); + u |= (l << 2*i); + L[8*k + i] = l; + } + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + const uint16_t * neighbours = kneighbors_q2xs - kmap_q2xs[u] - 1; + grid_index = iq2_find_best_neighbour(neighbours, kgrid_q2xs, xval + 8*k, waux + 8*k, scale, L + 8*k); + } + } + float sumqx = 0, sumq2 = 0; + for (int i = 0; i < 16; ++i) { + float w = weight[i]; + float q = 2*L[i] + 1; + sumqx += w*xval[i]*q; + sumq2 += w*q*q; + } + if (sumq2 > 0) scale = sumqx/sumq2; + } + if (scale < 0) { + scale = -scale; + for (int k = 0; k < 2; ++k) block_signs[k] = ~block_signs[k]; + } + for (int k = 0; k < 2; ++k) { + uint16_t u = 0; + for (int i = 0; i < 8; ++i) u |= (L[8*k+i] << 2*i); + int grid_index = kmap_q2xs[u]; + if (grid_index < 0) { + printf("Oops: found point %u not on grid:", u); + for (int i = 0; i < 8; ++i) printf(" %d", L[8*k+i]); + printf("\n"); + GGML_ASSERT(false); + } + const int i8 = 2*ib + k; + y[ibl].qs[i8] = grid_index & 255; + y[ibl].qh[i8/4] |= ((grid_index >> 8) << 2*(i8%4)); + y[ibl].qs[QK_K/8 + i8] = block_signs[k]; + } + GGML_ASSERT(scale >= 0); + scales[ib] = scale; + max_scale = MAX(max_scale, scale); + } + + if (!max_scale) { + continue; + } + + float d = max_scale/31; + y[ibl].d = GGML_FP32_TO_FP16(d * 0.9875f); + float id = 1/d; + for (int ib = 0; ib < QK_K/16; ++ib) { + int l = nearest_int(0.5f*(id*scales[ib]-1)); + l = MAX(0, MIN(15, l)); + if (ib%2 == 0) y[ibl].scales[ib/2] = l; + else y[ibl].scales[ib/2] |= (l << 4); + } + } +} + +size_t quantize_iq2_s(const float * restrict src, void * restrict dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { + GGML_ASSERT(n_per_row%QK_K == 0); + int64_t nblock = n_per_row/QK_K; + char * qrow = (char *)dst; + for (int64_t row = 0; row < nrow; ++row) { + quantize_row_iq2_s_impl(src, qrow, n_per_row, quant_weights); + src += n_per_row; + qrow += nblock*sizeof(block_iq2_s); + } + return nrow * nblock * sizeof(block_iq2_s); +} + +void quantize_row_iq2_s_reference(const float * restrict x, block_iq2_s * restrict y, int64_t k) { + assert(k % QK_K == 0); + quantize_iq2_s(x, y, 1, k, NULL); +} + +void quantize_row_iq2_s(const float * restrict x, void * restrict vy, int64_t k) { + assert(k % QK_K == 0); + block_iq2_s * restrict y = vy; + quantize_row_iq2_s_reference(x, y, k); +} diff --git a/bindings/ruby/ext/ggml-quants.h b/bindings/ruby/ext/ggml-quants.h new file mode 100644 index 0000000000000000000000000000000000000000..4d436a8f06b3e5081205dd568eb12d17443d4ee0 --- /dev/null +++ b/bindings/ruby/ext/ggml-quants.h @@ -0,0 +1,133 @@ +#pragma once + +#define GGML_COMMON_DECL_C +#include "ggml-common.h" + +#include "ggml.h" + +// GGML internal header + +#ifdef __cplusplus +extern "C" { +#endif + +// Quantization +void quantize_row_q4_0_reference(const float * GGML_RESTRICT x, block_q4_0 * GGML_RESTRICT y, int64_t k); +void quantize_row_q4_1_reference(const float * GGML_RESTRICT x, block_q4_1 * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_0_reference(const float * GGML_RESTRICT x, block_q5_0 * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_1_reference(const float * GGML_RESTRICT x, block_q5_1 * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_0_reference(const float * GGML_RESTRICT x, block_q8_0 * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_1_reference(const float * GGML_RESTRICT x, block_q8_1 * GGML_RESTRICT y, int64_t k); + +void quantize_row_q2_K_reference(const float * GGML_RESTRICT x, block_q2_K * GGML_RESTRICT y, int64_t k); +void quantize_row_q3_K_reference(const float * GGML_RESTRICT x, block_q3_K * GGML_RESTRICT y, int64_t k); +void quantize_row_q4_K_reference(const float * GGML_RESTRICT x, block_q4_K * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_K_reference(const float * GGML_RESTRICT x, block_q5_K * GGML_RESTRICT y, int64_t k); +void quantize_row_q6_K_reference(const float * GGML_RESTRICT x, block_q6_K * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_K_reference(const float * GGML_RESTRICT x, block_q8_K * GGML_RESTRICT y, int64_t k); + +void quantize_row_iq3_xxs_reference(const float * GGML_RESTRICT x, block_iq3_xxs * GGML_RESTRICT y, int64_t k); +void quantize_row_iq4_nl_reference (const float * GGML_RESTRICT x, block_iq4_nl * GGML_RESTRICT y, int64_t k); +void quantize_row_iq4_xs_reference (const float * GGML_RESTRICT x, block_iq4_xs * GGML_RESTRICT y, int64_t k); +void quantize_row_iq3_s_reference (const float * GGML_RESTRICT x, block_iq3_s * GGML_RESTRICT y, int64_t k); +void quantize_row_iq2_s_reference (const float * GGML_RESTRICT x, block_iq2_s * GGML_RESTRICT y, int64_t k); + +void quantize_row_q4_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q4_1(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_1(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_1(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); + +void quantize_row_q2_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q3_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q4_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q5_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q6_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_q8_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); + +void quantize_row_iq3_xxs(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_iq4_nl (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_iq4_xs (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_iq3_s (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); +void quantize_row_iq2_s (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k); + +// Dequantization +void dequantize_row_q4_0(const block_q4_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q4_1(const block_q4_1 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q5_0(const block_q5_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q5_1(const block_q5_1 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q8_0(const block_q8_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +//void dequantize_row_q8_1(const block_q8_1 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); + +void dequantize_row_q2_K(const block_q2_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q3_K(const block_q3_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q4_K(const block_q4_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q5_K(const block_q5_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q6_K(const block_q6_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_q8_K(const block_q8_K * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); + +void dequantize_row_iq2_xxs(const block_iq2_xxs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq2_xs (const block_iq2_xs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq2_s (const block_iq2_s * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq3_xxs(const block_iq3_xxs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq1_s (const block_iq1_s * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq1_m (const block_iq1_m * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq4_nl (const block_iq4_nl * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq4_xs (const block_iq4_xs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); +void dequantize_row_iq3_s (const block_iq3_s * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k); + +// Dot product +void ggml_vec_dot_q4_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q4_1_q8_1(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q5_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q5_1_q8_1(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q8_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); + +void ggml_vec_dot_q2_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q3_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q4_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q5_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_q6_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); + +void ggml_vec_dot_iq2_xxs_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq2_xs_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq2_s_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq3_xxs_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq1_s_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq1_m_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq4_nl_q8_0 (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq4_xs_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); +void ggml_vec_dot_iq3_s_q8_K (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc); + +// Quantization utilizing an importance matrix (a.k.a. "Activation aWare Quantization") +size_t quantize_iq2_xxs(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq2_xs (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq2_s (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq3_xxs(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq1_s (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq1_m (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq4_nl (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq4_xs (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_iq3_s (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); + +size_t quantize_q2_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q3_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q4_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q5_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q6_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q4_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q4_1(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q5_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q5_1(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); +size_t quantize_q8_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix); + +void iq2xs_init_impl(enum ggml_type type); +void iq2xs_free_impl(enum ggml_type type); +void iq3xs_init_impl(int grid_size); +void iq3xs_free_impl(int grid_size); + +#ifdef __cplusplus +} +#endif + diff --git a/bindings/ruby/ext/ggml-sycl.h b/bindings/ruby/ext/ggml-sycl.h new file mode 100644 index 0000000000000000000000000000000000000000..a9f776fc1dd59786f84b7b015d90c585f6d08267 --- /dev/null +++ b/bindings/ruby/ext/ggml-sycl.h @@ -0,0 +1,49 @@ +// +// MIT license +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GGML_SYCL_MAX_DEVICES 48 +#define GGML_SYCL_NAME "SYCL" + +// backend API +GGML_API ggml_backend_t ggml_backend_sycl_init(int device); + +// devide buffer +GGML_API ggml_backend_buffer_type_t ggml_backend_sycl_buffer_type(int device); + +// split tensor buffer that splits matrices by rows across multiple devices +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_sycl_split_buffer_type(const float * tensor_split); + +// pinned host buffer for use with the CPU backend for faster copies between CPU and GPU +GGML_API ggml_backend_buffer_type_t ggml_backend_sycl_host_buffer_type(void); + +GGML_API void ggml_backend_sycl_print_sycl_devices(void); +GGML_API GGML_CALL void ggml_sycl_get_gpu_list(int *id_list, int max_len); +GGML_API GGML_CALL void ggml_sycl_get_device_description(int device, char *description, size_t description_size); +GGML_API GGML_CALL int ggml_backend_sycl_get_device_count(); +GGML_API GGML_CALL void ggml_backend_sycl_get_device_memory(int device, size_t *free, size_t *total); +GGML_API GGML_CALL int ggml_backend_sycl_get_device_index(int device_id); + +// TODO: these are temporary +// ref: https://github.com/ggerganov/llama.cpp/pull/6022#issuecomment-1992615670 +GGML_API GGML_CALL int ggml_backend_sycl_get_device_id(int device_index); +GGML_API GGML_CALL void ggml_backend_sycl_set_single_device_mode(int main_gpu_id); +GGML_API GGML_CALL void ggml_backend_sycl_set_mul_device_mode(); + +// SYCL doesn't support registering host memory, keep here for reference +// GGML_API GGML_CALL bool ggml_backend_sycl_register_host_buffer(void * buffer, size_t size); +// GGML_API GGML_CALL void ggml_backend_sycl_unregister_host_buffer(void * buffer); +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ggml-vulkan.h b/bindings/ruby/ext/ggml-vulkan.h new file mode 100644 index 0000000000000000000000000000000000000000..af661c2d7d563e83dac6046f2bceac3d063bccb8 --- /dev/null +++ b/bindings/ruby/ext/ggml-vulkan.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ggml.h" +#include "ggml-backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GGML_VK_NAME "Vulkan" +#define GGML_VK_MAX_DEVICES 16 + +GGML_API void ggml_vk_instance_init(void); + +// backend API +GGML_API GGML_CALL ggml_backend_t ggml_backend_vk_init(size_t dev_num); + +GGML_API GGML_CALL bool ggml_backend_is_vk(ggml_backend_t backend); +GGML_API GGML_CALL int ggml_backend_vk_get_device_count(void); +GGML_API GGML_CALL void ggml_backend_vk_get_device_description(int device, char * description, size_t description_size); +GGML_API GGML_CALL void ggml_backend_vk_get_device_memory(int device, size_t * free, size_t * total); + +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_vk_buffer_type(size_t dev_num); +// pinned host buffer for use with the CPU backend for faster copies between CPU and GPU +GGML_API GGML_CALL ggml_backend_buffer_type_t ggml_backend_vk_host_buffer_type(void); + +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ruby_whisper.cpp b/bindings/ruby/ext/ruby_whisper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d9334539b89219e76360857255d5ef7a8794d60 --- /dev/null +++ b/bindings/ruby/ext/ruby_whisper.cpp @@ -0,0 +1,418 @@ +#include +#include "ruby_whisper.h" +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOOL_PARAMS_SETTER(self, prop, value) \ + ruby_whisper_params *rwp; \ + Data_Get_Struct(self, ruby_whisper_params, rwp); \ + if (value == Qfalse || value == Qnil) { \ + rwp->params.prop = false; \ + } else { \ + rwp->params.prop = true; \ + } \ + return value; \ + +#define BOOL_PARAMS_GETTER(self, prop) \ + ruby_whisper_params *rwp; \ + Data_Get_Struct(self, ruby_whisper_params, rwp); \ + if (rwp->params.prop) { \ + return Qtrue; \ + } else { \ + return Qfalse; \ + } + +VALUE mWhisper; +VALUE cContext; +VALUE cParams; + +static void ruby_whisper_free(ruby_whisper *rw) { + if (rw->context) { + whisper_free(rw->context); + rw->context = NULL; + } +} +static void ruby_whisper_params_free(ruby_whisper_params *rwp) { +} + +void rb_whisper_mark(ruby_whisper *rw) { + // call rb_gc_mark on any ruby references in rw +} + +void rb_whisper_free(ruby_whisper *rw) { + ruby_whisper_free(rw); + free(rw); +} + +void rb_whisper_params_mark(ruby_whisper_params *rwp) { +} + +void rb_whisper_params_free(ruby_whisper_params *rwp) { + ruby_whisper_params_free(rwp); + free(rwp); +} + +static VALUE ruby_whisper_allocate(VALUE klass) { + ruby_whisper *rw; + rw = ALLOC(ruby_whisper); + rw->context = NULL; + return Data_Wrap_Struct(klass, rb_whisper_mark, rb_whisper_free, rw); +} + +static VALUE ruby_whisper_params_allocate(VALUE klass) { + ruby_whisper_params *rwp; + rwp = ALLOC(ruby_whisper_params); + rwp->params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + return Data_Wrap_Struct(klass, rb_whisper_params_mark, rb_whisper_params_free, rwp); +} + +static VALUE ruby_whisper_initialize(int argc, VALUE *argv, VALUE self) { + ruby_whisper *rw; + VALUE whisper_model_file_path; + + // TODO: we can support init from buffer here too maybe another ruby object to expose + rb_scan_args(argc, argv, "01", &whisper_model_file_path); + Data_Get_Struct(self, ruby_whisper, rw); + + if (!rb_respond_to(whisper_model_file_path, rb_intern("to_s"))) { + rb_raise(rb_eRuntimeError, "Expected file path to model to initialize Whisper::Context"); + } + rw->context = whisper_init_from_file_with_params(StringValueCStr(whisper_model_file_path), whisper_context_default_params()); + if (rw->context == nullptr) { + rb_raise(rb_eRuntimeError, "error: failed to initialize whisper context"); + } + return self; +} + +/* + * transcribe a single file + * can emit to a block results + * + **/ +static VALUE ruby_whisper_transcribe(int argc, VALUE *argv, VALUE self) { + ruby_whisper *rw; + ruby_whisper_params *rwp; + VALUE wave_file_path, blk, params; + + rb_scan_args(argc, argv, "02&", &wave_file_path, ¶ms, &blk); + Data_Get_Struct(self, ruby_whisper, rw); + Data_Get_Struct(params, ruby_whisper_params, rwp); + + if (!rb_respond_to(wave_file_path, rb_intern("to_s"))) { + rb_raise(rb_eRuntimeError, "Expected file path to wave file"); + } + + std::string fname_inp = StringValueCStr(wave_file_path); + + std::vector pcmf32; // mono-channel F32 PCM + std::vector> pcmf32s; // stereo-channel F32 PCM + + // WAV input - this is directly from main.cpp example + { + drwav wav; + std::vector wav_data; // used for pipe input from stdin + + if (fname_inp == "-") { + { + uint8_t buf[1024]; + while (true) { + const size_t n = fread(buf, 1, sizeof(buf), stdin); + if (n == 0) { + break; + } + wav_data.insert(wav_data.end(), buf, buf + n); + } + } + + if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) { + fprintf(stderr, "error: failed to open WAV file from stdin\n"); + return self; + } + + fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, wav_data.size()); + } else if (drwav_init_file(&wav, fname_inp.c_str(), nullptr) == false) { + fprintf(stderr, "error: failed to open '%s' as WAV file\n", fname_inp.c_str()); + return self; + } + + if (wav.channels != 1 && wav.channels != 2) { + fprintf(stderr, "WAV file '%s' must be mono or stereo\n", fname_inp.c_str()); + return self; + } + + if (rwp->diarize && wav.channels != 2 && rwp->params.print_timestamps == false) { + fprintf(stderr, "WAV file '%s' must be stereo for diarization and timestamps have to be enabled\n", fname_inp.c_str()); + return self; + } + + if (wav.sampleRate != WHISPER_SAMPLE_RATE) { + fprintf(stderr, "WAV file '%s' must be %i kHz\n", fname_inp.c_str(), WHISPER_SAMPLE_RATE/1000); + return self; + } + + if (wav.bitsPerSample != 16) { + fprintf(stderr, "WAV file '%s' must be 16-bit\n", fname_inp.c_str()); + return self; + } + + const uint64_t n = wav_data.empty() ? wav.totalPCMFrameCount : wav_data.size()/(wav.channels*wav.bitsPerSample/8); + + std::vector pcm16; + pcm16.resize(n*wav.channels); + drwav_read_pcm_frames_s16(&wav, n, pcm16.data()); + drwav_uninit(&wav); + + // convert to mono, float + pcmf32.resize(n); + if (wav.channels == 1) { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[i])/32768.0f; + } + } else { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[2*i] + pcm16[2*i + 1])/65536.0f; + } + } + + if (rwp->diarize) { + // convert to stereo, float + pcmf32s.resize(2); + + pcmf32s[0].resize(n); + pcmf32s[1].resize(n); + for (uint64_t i = 0; i < n; i++) { + pcmf32s[0][i] = float(pcm16[2*i])/32768.0f; + pcmf32s[1][i] = float(pcm16[2*i + 1])/32768.0f; + } + } + } + { + static bool is_aborted = false; // NOTE: this should be atomic to avoid data race + + rwp->params.encoder_begin_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, void * user_data) { + bool is_aborted = *(bool*)user_data; + return !is_aborted; + }; + rwp->params.encoder_begin_callback_user_data = &is_aborted; + } + + if (whisper_full_parallel(rw->context, rwp->params, pcmf32.data(), pcmf32.size(), 1) != 0) { + fprintf(stderr, "failed to process audio\n"); + return self; + } + const int n_segments = whisper_full_n_segments(rw->context); + VALUE output = rb_str_new2(""); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(rw->context, i); + output = rb_str_concat(output, rb_str_new2(text)); + } + VALUE idCall = rb_intern("call"); + if (blk != Qnil) { + rb_funcall(blk, idCall, 1, output); + } + return self; +} + +/* + * params.language = "auto" | "en", etc... + */ +static VALUE ruby_whisper_params_set_language(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (value == Qfalse || value == Qnil) { + rwp->params.language = "auto"; + } else { + rwp->params.language = StringValueCStr(value); + } + return value; +} +static VALUE ruby_whisper_params_get_language(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (rwp->params.language) { + return rb_str_new2(rwp->params.language); + } else { + return rb_str_new2("auto"); + } +} +static VALUE ruby_whisper_params_set_translate(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, translate, value) +} +static VALUE ruby_whisper_params_get_translate(VALUE self) { + BOOL_PARAMS_GETTER(self, translate) +} +static VALUE ruby_whisper_params_set_no_context(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, no_context, value) +} +static VALUE ruby_whisper_params_get_no_context(VALUE self) { + BOOL_PARAMS_GETTER(self, no_context) +} +static VALUE ruby_whisper_params_set_single_segment(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, single_segment, value) +} +static VALUE ruby_whisper_params_get_single_segment(VALUE self) { + BOOL_PARAMS_GETTER(self, single_segment) +} +static VALUE ruby_whisper_params_set_print_special(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_special, value) +} +static VALUE ruby_whisper_params_get_print_special(VALUE self) { + BOOL_PARAMS_GETTER(self, print_special) +} +static VALUE ruby_whisper_params_set_print_progress(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_progress, value) +} +static VALUE ruby_whisper_params_get_print_progress(VALUE self) { + BOOL_PARAMS_GETTER(self, print_progress) +} +static VALUE ruby_whisper_params_set_print_realtime(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_realtime, value) +} +static VALUE ruby_whisper_params_get_print_realtime(VALUE self) { + BOOL_PARAMS_GETTER(self, print_realtime) +} +static VALUE ruby_whisper_params_set_print_timestamps(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_timestamps, value) +} +static VALUE ruby_whisper_params_get_print_timestamps(VALUE self) { + BOOL_PARAMS_GETTER(self, print_timestamps) +} +static VALUE ruby_whisper_params_set_suppress_blank(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, suppress_blank, value) +} +static VALUE ruby_whisper_params_get_suppress_blank(VALUE self) { + BOOL_PARAMS_GETTER(self, suppress_blank) +} +static VALUE ruby_whisper_params_set_suppress_non_speech_tokens(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, suppress_non_speech_tokens, value) +} +static VALUE ruby_whisper_params_get_suppress_non_speech_tokens(VALUE self) { + BOOL_PARAMS_GETTER(self, suppress_non_speech_tokens) +} +static VALUE ruby_whisper_params_get_token_timestamps(VALUE self) { + BOOL_PARAMS_GETTER(self, token_timestamps) +} +static VALUE ruby_whisper_params_set_token_timestamps(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, token_timestamps, value) +} +static VALUE ruby_whisper_params_get_split_on_word(VALUE self) { + BOOL_PARAMS_GETTER(self, split_on_word) +} +static VALUE ruby_whisper_params_set_split_on_word(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, split_on_word, value) +} +static VALUE ruby_whisper_params_get_diarize(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (rwp->diarize) { + return Qtrue; + } else { + return Qfalse; + } +} +static VALUE ruby_whisper_params_set_diarize(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (value == Qfalse || value == Qnil) { + rwp->diarize = false; + } else { + rwp->diarize = true; + } \ + return value; +} + +static VALUE ruby_whisper_params_get_offset(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.offset_ms); +} +static VALUE ruby_whisper_params_set_offset(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.offset_ms = NUM2INT(value); + return value; +} +static VALUE ruby_whisper_params_get_duration(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.duration_ms); +} +static VALUE ruby_whisper_params_set_duration(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.duration_ms = NUM2INT(value); + return value; +} + +static VALUE ruby_whisper_params_get_max_text_tokens(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.n_max_text_ctx); +} +static VALUE ruby_whisper_params_set_max_text_tokens(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.n_max_text_ctx = NUM2INT(value); + return value; +} + +void Init_whisper() { + mWhisper = rb_define_module("Whisper"); + cContext = rb_define_class_under(mWhisper, "Context", rb_cObject); + cParams = rb_define_class_under(mWhisper, "Params", rb_cObject); + + rb_define_alloc_func(cContext, ruby_whisper_allocate); + rb_define_method(cContext, "initialize", ruby_whisper_initialize, -1); + + rb_define_method(cContext, "transcribe", ruby_whisper_transcribe, -1); + + rb_define_alloc_func(cParams, ruby_whisper_params_allocate); + + rb_define_method(cParams, "language=", ruby_whisper_params_set_language, 1); + rb_define_method(cParams, "language", ruby_whisper_params_get_language, 0); + rb_define_method(cParams, "translate=", ruby_whisper_params_set_translate, 1); + rb_define_method(cParams, "translate", ruby_whisper_params_get_translate, 0); + rb_define_method(cParams, "no_context=", ruby_whisper_params_set_no_context, 1); + rb_define_method(cParams, "no_context", ruby_whisper_params_get_no_context, 0); + rb_define_method(cParams, "single_segment=", ruby_whisper_params_set_single_segment, 1); + rb_define_method(cParams, "single_segment", ruby_whisper_params_get_single_segment, 0); + rb_define_method(cParams, "print_special", ruby_whisper_params_get_print_special, 0); + rb_define_method(cParams, "print_special=", ruby_whisper_params_set_print_special, 1); + rb_define_method(cParams, "print_progress", ruby_whisper_params_get_print_progress, 0); + rb_define_method(cParams, "print_progress=", ruby_whisper_params_set_print_progress, 1); + rb_define_method(cParams, "print_realtime", ruby_whisper_params_get_print_realtime, 0); + rb_define_method(cParams, "print_realtime=", ruby_whisper_params_set_print_realtime, 1); + rb_define_method(cParams, "print_timestamps", ruby_whisper_params_get_print_timestamps, 0); + rb_define_method(cParams, "print_timestamps=", ruby_whisper_params_set_print_timestamps, 1); + rb_define_method(cParams, "suppress_blank", ruby_whisper_params_get_suppress_blank, 0); + rb_define_method(cParams, "suppress_blank=", ruby_whisper_params_set_suppress_blank, 1); + rb_define_method(cParams, "suppress_non_speech_tokens", ruby_whisper_params_get_suppress_non_speech_tokens, 0); + rb_define_method(cParams, "suppress_non_speech_tokens=", ruby_whisper_params_set_suppress_non_speech_tokens, 1); + rb_define_method(cParams, "token_timestamps", ruby_whisper_params_get_token_timestamps, 0); + rb_define_method(cParams, "token_timestamps=", ruby_whisper_params_set_token_timestamps, 1); + rb_define_method(cParams, "split_on_word", ruby_whisper_params_get_split_on_word, 0); + rb_define_method(cParams, "split_on_word=", ruby_whisper_params_set_split_on_word, 1); + rb_define_method(cParams, "diarize", ruby_whisper_params_get_diarize, 0); + rb_define_method(cParams, "diarize=", ruby_whisper_params_set_diarize, 1); + + rb_define_method(cParams, "offset", ruby_whisper_params_get_offset, 0); + rb_define_method(cParams, "offset=", ruby_whisper_params_set_offset, 1); + rb_define_method(cParams, "duration", ruby_whisper_params_get_duration, 0); + rb_define_method(cParams, "duration=", ruby_whisper_params_set_duration, 1); + + rb_define_method(cParams, "max_text_tokens", ruby_whisper_params_get_max_text_tokens, 0); + rb_define_method(cParams, "max_text_tokens=", ruby_whisper_params_set_max_text_tokens, 1); +} +#ifdef __cplusplus +} +#endif diff --git a/bindings/ruby/ext/ruby_whisper.h b/bindings/ruby/ext/ruby_whisper.h new file mode 100644 index 0000000000000000000000000000000000000000..8c35b7cb65c08e3380b895c83ac49b966dd3c0e1 --- /dev/null +++ b/bindings/ruby/ext/ruby_whisper.h @@ -0,0 +1,15 @@ +#ifndef __RUBY_WHISPER_H +#define __RUBY_WHISPER_H + +#include "whisper.h" + +typedef struct { + struct whisper_context *context; +} ruby_whisper; + +typedef struct { + struct whisper_full_params params; + bool diarize; +} ruby_whisper_params; + +#endif diff --git a/bindings/ruby/tests/test_whisper.rb b/bindings/ruby/tests/test_whisper.rb new file mode 100644 index 0000000000000000000000000000000000000000..3700671bce6e15694a7f6daad8ab075a8e274641 --- /dev/null +++ b/bindings/ruby/tests/test_whisper.rb @@ -0,0 +1,131 @@ +TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), '..')) +EXTDIR = File.join(TOPDIR, 'ext') +#$LIBDIR = File.join(TOPDIR, 'lib') +#$:.unshift(LIBDIR) +$:.unshift(EXTDIR) + +require 'whisper' +require 'test/unit' + +class TestWhisper < Test::Unit::TestCase + def setup + @params = Whisper::Params.new + end + + def test_language + @params.language = "en" + assert_equal @params.language, "en" + @params.language = "auto" + assert_equal @params.language, "auto" + end + + def test_offset + @params.offset = 10_000 + assert_equal @params.offset, 10_000 + @params.offset = 0 + assert_equal @params.offset, 0 + end + + def test_duration + @params.duration = 60_000 + assert_equal @params.duration, 60_000 + @params.duration = 0 + assert_equal @params.duration, 0 + end + + def test_max_text_tokens + @params.max_text_tokens = 300 + assert_equal @params.max_text_tokens, 300 + @params.max_text_tokens = 0 + assert_equal @params.max_text_tokens, 0 + end + + def test_translate + @params.translate = true + assert @params.translate + @params.translate = false + assert !@params.translate + end + + def test_no_context + @params.no_context = true + assert @params.no_context + @params.no_context = false + assert !@params.no_context + end + + def test_single_segment + @params.single_segment = true + assert @params.single_segment + @params.single_segment = false + assert !@params.single_segment + end + + def test_print_special + @params.print_special = true + assert @params.print_special + @params.print_special = false + assert !@params.print_special + end + + def test_print_progress + @params.print_progress = true + assert @params.print_progress + @params.print_progress = false + assert !@params.print_progress + end + + def test_print_realtime + @params.print_realtime = true + assert @params.print_realtime + @params.print_realtime = false + assert !@params.print_realtime + end + + def test_print_timestamps + @params.print_timestamps = true + assert @params.print_timestamps + @params.print_timestamps = false + assert !@params.print_timestamps + end + + def test_suppress_blank + @params.suppress_blank = true + assert @params.suppress_blank + @params.suppress_blank = false + assert !@params.suppress_blank + end + + def test_suppress_non_speech_tokens + @params.suppress_non_speech_tokens = true + assert @params.suppress_non_speech_tokens + @params.suppress_non_speech_tokens = false + assert !@params.suppress_non_speech_tokens + end + + def test_token_timestamps + @params.token_timestamps = true + assert @params.token_timestamps + @params.token_timestamps = false + assert !@params.token_timestamps + end + + def test_split_on_word + @params.split_on_word = true + assert @params.split_on_word + @params.split_on_word = false + assert !@params.split_on_word + end + + def test_whisper + @whisper = Whisper::Context.new(File.join(TOPDIR, '..', '..', 'models', 'ggml-base.en.bin')) + params = Whisper::Params.new + params.print_timestamps = false + + jfk = File.join(TOPDIR, '..', '..', 'samples', 'jfk.wav') + @whisper.transcribe(jfk, params) {|text| + assert_match /ask not what your country can do for you, ask what you can do for your country/, text + } + end + +end diff --git a/bindings/ruby/whispercpp.gemspec b/bindings/ruby/whispercpp.gemspec new file mode 100644 index 0000000000000000000000000000000000000000..508a6a940520337ca02dc6f3af8521f15b43f284 --- /dev/null +++ b/bindings/ruby/whispercpp.gemspec @@ -0,0 +1,28 @@ +Gem::Specification.new do |s| + s.name = "whispercpp" + s.authors = ["Georgi Gerganov", "Todd A. Fisher"] + s.version = '1.3.0' + s.date = '2024-05-14' + s.description = %q{High-performance inference of OpenAI's Whisper automatic speech recognition (ASR) model via Ruby} + s.email = 'todd.fisher@gmail.com' + s.extra_rdoc_files = ['LICENSE', 'README.md'] + + s.files = ["LICENSE", "README.md", "Rakefile", "ext/extconf.rb", "ext/ggml.c", "ext/ruby_whisper.cpp", "ext/whisper.cpp", "ext/dr_wav.h", "ext/ggml.h", "ext/ruby_whisper.h", "ext/whisper.h"] + + #### Load-time details + s.require_paths = ['lib','ext'] + s.summary = %q{Ruby whisper.cpp bindings} + s.test_files = ["tests/test_whisper.rb"] + + s.extensions << 'ext/extconf.rb' + + + #### Documentation and testing. + s.homepage = 'https://github.com/ggerganov/whisper.cpp' + s.rdoc_options = ['--main', '../../README.md'] + + + s.platform = Gem::Platform::RUBY + + s.licenses = ['MIT'] +end diff --git a/cmake/DefaultTargetOptions.cmake b/cmake/DefaultTargetOptions.cmake new file mode 100644 index 0000000000000000000000000000000000000000..fc118a2bd34a7c0b690b97babf7eb780eb871608 --- /dev/null +++ b/cmake/DefaultTargetOptions.cmake @@ -0,0 +1,17 @@ +# Set the default compile features and properties for a target. + +if (NOT TARGET) + message(FATAL_ERROR "TARGET not set before including DefaultTargetOptions") +endif() + +target_compile_features(${TARGET} + PRIVATE + cxx_std_11 + ) + +set_target_properties(${TARGET} + PROPERTIES + EXPORT_COMPILE_COMMANDS ON + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" +) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake new file mode 100644 index 0000000000000000000000000000000000000000..bb6aff6c93d5d6d6ba5a6e1f1066cc9941a1f6c6 --- /dev/null +++ b/cmake/FindFFmpeg.cmake @@ -0,0 +1,163 @@ +# From +# https://github.com/snikulov/cmake-modules/blob/master/FindFFmpeg.cmake +# +# vim: ts=2 sw=2 +# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC) +# +# Once done this will define +# FFMPEG_FOUND - System has the all required components. +# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. +# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. +# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. +# +# For each of the components it will additionally set. +# - AVCODEC +# - AVDEVICE +# - AVFORMAT +# - AVFILTER +# - AVUTIL +# - POSTPROC +# - SWSCALE +# the following variables will be defined +# _FOUND - System has +# _INCLUDE_DIRS - Include directory necessary for using the headers +# _LIBRARIES - Link these to use +# _DEFINITIONS - Compiler switches required for using +# _VERSION - The components version +# +# Copyright (c) 2006, Matthias Kretz, +# Copyright (c) 2008, Alexander Neundorf, +# Copyright (c) 2011, Michael Jansen, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +include(FindPackageHandleStandardArgs) + +# The default components were taken from a survey over other FindFFMPEG.cmake files +if (NOT FFmpeg_FIND_COMPONENTS) + set(FFmpeg_FIND_COMPONENTS AVFORMAT AVCODEC AVUTIL SWRESAMPLE) +endif() + +# +### Macro: set_component_found +# +# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. +# +macro(set_component_found _component ) + if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) + message(DEBUG " - ${_component} found.") + set(${_component}_FOUND TRUE) + else () + message(DEBUG " - ${_component} not found.") + endif () +endmacro() + +# +### Macro: find_component +# +# Checks for the given component by invoking pkgconfig and then looking up the libraries and +# include directories. +# +macro(find_component _component _pkgconfig _library _header) + + if (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(PC_${_component} ${_pkgconfig}) + message(STATUS "Pkgconfig found: ${PC_${_component}_INCLUDEDIR}") + message(STATUS "Pkgconfig found: ${PC_${_component}_INCLUDE_DIRS}") + message(STATUS "${PC_${_component}_CFLAGS}") + endif () + endif (NOT WIN32) + + + find_path(${_component}_INCLUDE_DIRS ${_header} + HINTS + ${PC_${_component}_INCLUDEDIR} + ${PC_${_component}_INCLUDE_DIRS} + PATH_SUFFIXES + ffmpeg + ) + + # CMake's default is to search first for shared libraries and then for static libraries. + # Todo later: add option to prefer static libs over dynamic: + find_library(${_component}_LIBRARIES NAMES ${_library} lib${_library}.a + HINTS + ${PC_${_component}_LIBDIR} + ${PC_${_component}_LIBRARY_DIRS} + ) + + set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") + set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") + + set_component_found(${_component}) + + mark_as_advanced( + ${_component}_INCLUDE_DIRS + ${_component}_LIBRARIES + ${_component}_DEFINITIONS + ${_component}_VERSION) + +endmacro() + + +# Check for cached results. If there are skip the costly part. +if (NOT FFMPEG_LIBRARIES) + + # Check for all possible component. + find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) + find_component(AVFORMAT libavformat avformat libavformat/avformat.h) + find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) + #find_component(AVRESAMPLE libavresample avresample libavresample/avresample.h) # old name for swresample + find_component(AVUTIL libavutil avutil libavutil/avutil.h) + find_component(AVFILTER libavfilter avfilter libavfilter/avfilter.h) + find_component(SWSCALE libswscale swscale libswscale/swscale.h) + find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) + find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h) + + # Check if the required components were found and add their stuff to the FFMPEG_* vars. + foreach (_component ${FFmpeg_FIND_COMPONENTS}) + if (${_component}_FOUND) + # message(STATUS "Required component ${_component} present.") + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) + set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) + list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) + else () + # message(STATUS "Required component ${_component} missing.") + endif () + endforeach () + + # Build the include path with duplicates removed. + if (FFMPEG_INCLUDE_DIRS) + list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) + endif () + + # cache the vars. + set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) + set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) + + mark_as_advanced(FFMPEG_INCLUDE_DIRS + FFMPEG_LIBRARIES + FFMPEG_DEFINITIONS) + +endif () + +# Now set the noncached _FOUND vars for the components. +# whisper.cpp does not need SWSCALE +foreach (_component AVCODEC AVDEVICE AVFORMAT AVRESAMPLE AVUTIL POSTPROCESS) + set_component_found(${_component}) +endforeach () + +# Compile the list of required vars +set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) +foreach (_component ${FFmpeg_FIND_COMPONENTS}) + list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) +endforeach () + +# Give a nice error message if some of the required vars are missing. +find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS}) + diff --git a/cmake/build-info.cmake b/cmake/build-info.cmake new file mode 100644 index 0000000000000000000000000000000000000000..ea3dc55c83439a91c9289760bc17b1b0dcd69aa1 --- /dev/null +++ b/cmake/build-info.cmake @@ -0,0 +1,58 @@ +set(BUILD_NUMBER 0) +set(BUILD_COMMIT "unknown") +set(BUILD_COMPILER "unknown") +set(BUILD_TARGET "unknown") + +# Look for git +find_package(Git) +if(NOT Git_FOUND) + find_program(GIT_EXECUTABLE NAMES git git.exe) + if(GIT_EXECUTABLE) + set(Git_FOUND TRUE) + message(STATUS "Found Git: ${GIT_EXECUTABLE}") + else() + message(WARNING "Git not found. Build info will not be accurate.") + endif() +endif() + +# Get the commit count and hash +if(Git_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE HEAD + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE RES + ) + if (RES EQUAL 0) + set(BUILD_COMMIT ${HEAD}) + endif() + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE COUNT + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE RES + ) + if (RES EQUAL 0) + set(BUILD_NUMBER ${COUNT}) + endif() +endif() + +if(MSVC) + set(BUILD_COMPILER "${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}") + set(BUILD_TARGET ${CMAKE_VS_PLATFORM_NAME}) +else() + execute_process( + COMMAND sh -c "$@ --version | head -1" _ ${CMAKE_C_COMPILER} + OUTPUT_VARIABLE OUT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(BUILD_COMPILER ${OUT}) + execute_process( + COMMAND ${CMAKE_C_COMPILER} -dumpmachine + OUTPUT_VARIABLE OUT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(BUILD_TARGET ${OUT}) +endif() diff --git a/cmake/git-vars.cmake b/cmake/git-vars.cmake new file mode 100644 index 0000000000000000000000000000000000000000..1a4c24ebf6adeb1126e626f56de601621179353d --- /dev/null +++ b/cmake/git-vars.cmake @@ -0,0 +1,22 @@ +find_package(Git) + +# the commit's SHA1 +execute_process(COMMAND + "${GIT_EXECUTABLE}" describe --match=NeVeRmAtCh --always --abbrev=8 + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_SHA1 + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + +# the date of the commit +execute_process(COMMAND + "${GIT_EXECUTABLE}" log -1 --format=%ad --date=local + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_DATE + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + +# the subject of the commit +execute_process(COMMAND + "${GIT_EXECUTABLE}" log -1 --format=%s + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_COMMIT_SUBJECT + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/cmake/whisper-config.cmake.in b/cmake/whisper-config.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..6a3fa22701fab8dd080f68d924610789ac768546 --- /dev/null +++ b/cmake/whisper-config.cmake.in @@ -0,0 +1,65 @@ +set(WHISPER_VERSION @WHISPER_INSTALL_VERSION@) +set(WHISPER_BUILD_COMMIT @WHISPER_BUILD_COMMIT@) +set(WHISPER_BUILD_NUMBER @WHISPER_BUILD_NUMBER@) +set(WHISPER_SHARED_LIB @BUILD_SHARED_LIBS@) + +set(GGML_BLAS @GGML_BLAS@) +set(GGML_CUDA @GGML_CUDA@) +set(GGML_METAL @GGML_METAL@) +set(GGML_HIPBLAS @GGML_HIPBLAS@) +set(GGML_ACCELERATE @GGML_ACCELERATE@) + +@PACKAGE_INIT@ + +set_and_check(WHISPER_INCLUDE_DIR "@PACKAGE_WHISPER_INCLUDE_INSTALL_DIR@") +set_and_check(WHISPER_LIB_DIR "@PACKAGE_WHISPER_LIB_INSTALL_DIR@") +set_and_check(WHISPER_BIN_DIR "@PACKAGE_WHISPER_BIN_INSTALL_DIR@") + +# Ensure transient dependencies satisfied + +find_package(Threads REQUIRED) + +if (APPLE AND GGML_ACCELERATE) + find_library(ACCELERATE_FRAMEWORK Accelerate REQUIRED) +endif() + +if (GGML_BLAS) + find_package(BLAS REQUIRED) +endif() + +if (GGML_CUDA) + find_package(CUDAToolkit REQUIRED) +endif() + +if (GGML_METAL) + find_library(FOUNDATION_LIBRARY Foundation REQUIRED) + find_library(METAL_FRAMEWORK Metal REQUIRED) + find_library(METALKIT_FRAMEWORK MetalKit REQUIRED) +endif() + +if (GGML_HIPBLAS) + find_package(hip REQUIRED) + find_package(hipblas REQUIRED) + find_package(rocblas REQUIRED) +endif() + +find_library(whisper_LIBRARY whisper + REQUIRED + HINTS ${WHISPER_LIB_DIR}) + +set(_whisper_link_deps "Threads::Threads" "@WHISPER_EXTRA_LIBS@") +set(_whisper_transient_defines "@WHISPER_TRANSIENT_DEFINES@") + +add_library(whisper UNKNOWN IMPORTED) + +set_target_properties(whisper + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${WHISPER_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${_whisper_link_deps}" + INTERFACE_COMPILE_DEFINITIONS "${_whisper_transient_defines}" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${whisper_LIBRARY}" + INTERFACE_COMPILE_FEATURES cxx_std_11 + POSITION_INDEPENDENT_CODE ON ) + +check_required_components(whisper) diff --git a/cmake/whisper.pc.in b/cmake/whisper.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..67aaafdeaae626353a615cc6d2a12af290d9f724 --- /dev/null +++ b/cmake/whisper.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: whisper +Description: Port of OpenAI's Whisper model in C/C++ +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lwhisper +Cflags: -I${includedir} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc091d716d1bae30ac935ec97fa59fae25cc01a5 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,146 @@ +# dependencies + +find_package(Threads REQUIRED) + +# third-party + +if (WHISPER_SDL2) + # SDL2 + find_package(SDL2 REQUIRED) + + string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) + + message(STATUS "SDL2_INCLUDE_DIRS = ${SDL2_INCLUDE_DIRS}") + message(STATUS "SDL2_LIBRARIES = ${SDL2_LIBRARIES}") +endif() + +if (WHISPER_CLBLAST) + find_package(CLBlast REQUIRED) +endif() + +# common + +set(TARGET common) + +unset(COMMON_EXTRA_LIBS) + +if (WHISPER_FFMPEG) + # As of cmake 3.27, there is no official cmake support for FindFFmpeg. + # Consequnelty we added a FindFFmpeg.cmake script the cmake subfolder: + # whisper.cpp does not need the full ffmpeg libs, just AVFORMAT AVCODEC AVUTIL SWRESAMPLE + # libswresample performs highly optimized audio resampling, rematrixing and sample format conversion operations + # libavcodec provides a generic encoding/decoding framework and contains multiple decoders and encoders for audio, video and subtitle streams, and several bitstream filters. + # libavformat provides a generic framework for multiplexing and demultiplexing (muxing and demuxing) audio, video and subtitle streams. + find_package(FFmpeg REQUIRED) + + if (NOT ${FFMPEG_FOUND}) + message(FATAL_ERROR "Cannot find ffmpeg libs/headers") + endif() + + message(STATUS "Found ffmpeg libs: ${FFMPEG_LIBRARIES}") + message(STATUS "Found ffmpeg headers in: ${FFMPEG_INCLUDE_DIRS}") + message(STATUS "ffmpeg definitions: ${FFMPEG_DEFINITIONS}") + message(STATUS "Found avformat ${AVFORMAT_VERSION}") + + include_directories(${FFMPEG_INCLUDE_DIRS}) + add_compile_definitions(WHISPER_FFMPEG) + + list(APPEND COMMON_EXTRA_LIBS ${FFMPEG_LIBRARIES}) + + set(COMMON_SOURCES_FFMPEG ffmpeg-transcode.cpp) +endif() + + +add_library(${TARGET} STATIC + common.h + common.cpp + common-ggml.h + common-ggml.cpp + grammar-parser.h + grammar-parser.cpp + ${COMMON_SOURCES_FFMPEG} + ) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE whisper ${COMMON_EXTRA_LIBS}) + +set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties(${TARGET} PROPERTIES FOLDER "libs") + +if (WHISPER_SDL2) + # common-sdl + + set(TARGET common-sdl) + + add_library(${TARGET} STATIC + common-sdl.h + common-sdl.cpp + ) + + include(DefaultTargetOptions) + + target_include_directories(${TARGET} PUBLIC ${SDL2_INCLUDE_DIRS}) + target_link_libraries (${TARGET} PRIVATE ${SDL2_LIBRARIES}) + + set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON) + set_target_properties(${TARGET} PROPERTIES FOLDER "libs") +endif() + +# add json lib +add_library(json_cpp INTERFACE) +target_include_directories(json_cpp INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +# examples + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +if (EMSCRIPTEN) + add_subdirectory(whisper.wasm) + set_target_properties(libmain PROPERTIES FOLDER "libs") + add_subdirectory(stream.wasm) + set_target_properties(libstream PROPERTIES FOLDER "libs") + add_subdirectory(command.wasm) + set_target_properties(libcommand PROPERTIES FOLDER "libs") + add_subdirectory(talk.wasm) + set_target_properties(libtalk PROPERTIES FOLDER "libs") + add_subdirectory(bench.wasm) + set_target_properties(libbench PROPERTIES FOLDER "libs") +elseif(CMAKE_JS_VERSION) + add_subdirectory(addon.node) + set_target_properties(addon.node PROPERTIES FOLDER "examples") +else() + add_subdirectory(main) + set_target_properties(main PROPERTIES FOLDER "examples") +if (WHISPER_SDL2) + add_subdirectory(stream) + set_target_properties(stream PROPERTIES FOLDER "examples") +endif (WHISPER_SDL2) + add_subdirectory(server) + set_target_properties(server PROPERTIES FOLDER "examples") +if (WHISPER_SDL2) + add_subdirectory(command) + set_target_properties(command PROPERTIES FOLDER "examples") +endif (WHISPER_SDL2) + add_subdirectory(bench) + set_target_properties(bench PROPERTIES FOLDER "examples") + add_subdirectory(quantize) + set_target_properties(quantize PROPERTIES FOLDER "examples") +if (WHISPER_SDL2) + add_subdirectory(talk) + set_target_properties(talk PROPERTIES FOLDER "examples") + add_subdirectory(talk-llama) + set_target_properties(talk-llama PROPERTIES FOLDER "examples") + add_subdirectory(lsp) + set_target_properties(lsp PROPERTIES FOLDER "examples") + if (GGML_SYCL) + add_subdirectory(sycl) + set_target_properties(sycl PROPERTIES FOLDER "examples") + endif() +endif (WHISPER_SDL2) +endif() + +if (WHISPER_SDL2) + add_subdirectory(wchess) + set_target_properties(wchess PROPERTIES FOLDER "examples") +endif (WHISPER_SDL2) diff --git a/examples/addon.node/.gitignore b/examples/addon.node/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b456cad9e5d758a42302f06518fe44b0c58642bc --- /dev/null +++ b/examples/addon.node/.gitignore @@ -0,0 +1,3 @@ +.idea +node_modules +build diff --git a/examples/addon.node/CMakeLists.txt b/examples/addon.node/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..29cb1a27d078942687b71bf66601b027b15edeb5 --- /dev/null +++ b/examples/addon.node/CMakeLists.txt @@ -0,0 +1,31 @@ +set(TARGET addon.node) + +# Base settings +#================================================================== +# env var supported by cmake-js +add_definitions(-DNAPI_VERSION=4) +include_directories(${CMAKE_JS_INC}) +#================================================================== + +add_library(${TARGET} SHARED ${CMAKE_JS_SRC} addon.cpp) +set_target_properties(${TARGET} PROPERTIES PREFIX "" SUFFIX ".node") + +include(DefaultTargetOptions) + +# Include N-API wrappers +#================================================================== +execute_process(COMMAND node -p "require('node-addon-api').include" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE NODE_ADDON_API_DIR + ) +string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) +string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) +target_include_directories(${TARGET} PRIVATE ${NODE_ADDON_API_DIR}) +#================================================================== + +target_link_libraries(${TARGET} ${CMAKE_JS_LIB} common whisper ${CMAKE_THREAD_LIBS_INIT}) + +if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET) + # Generate node.lib + execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS}) +endif() diff --git a/examples/addon.node/README.md b/examples/addon.node/README.md new file mode 100644 index 0000000000000000000000000000000000000000..16df7d95870cb13f7aa10a546b9584508bcc9cae --- /dev/null +++ b/examples/addon.node/README.md @@ -0,0 +1,37 @@ +# addon + +This is an addon demo that can **perform whisper model reasoning in `node` and `electron` environments**, based on [cmake-js](https://github.com/cmake-js/cmake-js). +It can be used as a reference for using the whisper.cpp project in other node projects. + +## Install + +```shell +npm install +``` + +## Compile + +Make sure it is in the project root directory and compiled with make-js. + +```shell +npx cmake-js compile -T addon.node -B Release +``` + +For Electron addon and cmake-js options, you can see [cmake-js](https://github.com/cmake-js/cmake-js) and make very few configuration changes. + +> Such as appointing special cmake path: +> ```shell +> npx cmake-js compile -c 'xxx/cmake' -T addon.node -B Release +> ``` + +## Run + +```shell +cd examples/addon.node + +node index.js --language='language' --model='model-path' --fname_inp='file-path' +``` + +Because this is a simple Demo, only the above parameters are set in the node environment. + +Other parameters can also be specified in the node environment. diff --git a/examples/addon.node/__test__/whisper.spec.js b/examples/addon.node/__test__/whisper.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..1ee888a1e009c862ce19d79f770378699a471d49 --- /dev/null +++ b/examples/addon.node/__test__/whisper.spec.js @@ -0,0 +1,30 @@ +const path = require("path"); +const { whisper } = require(path.join( + __dirname, + "../../../build/Release/addon.node" +)); +const { promisify } = require("util"); + +const whisperAsync = promisify(whisper); + +const whisperParamsMock = { + language: "en", + model: path.join(__dirname, "../../../models/ggml-base.en.bin"), + fname_inp: path.join(__dirname, "../../../samples/jfk.wav"), + use_gpu: true, + flash_attn: false, + no_prints: true, + comma_in_time: false, + translate: true, + no_timestamps: false, + audio_ctx: 0, +}; + +describe("Run whisper.node", () => { + test("it should receive a non-empty value", async () => { + let result = await whisperAsync(whisperParamsMock); + + expect(result.length).toBeGreaterThan(0); + }, 10000); +}); + diff --git a/examples/addon.node/addon.cpp b/examples/addon.node/addon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ada6ca508489e42729caf8fe01ebe1f38abbc01 --- /dev/null +++ b/examples/addon.node/addon.cpp @@ -0,0 +1,371 @@ +#include "napi.h" +#include "common.h" + +#include "whisper.h" + +#include +#include +#include +#include +#include + +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t n_processors = 1; + int32_t offset_t_ms = 0; + int32_t offset_n = 0; + int32_t duration_ms = 0; + int32_t max_context = -1; + int32_t max_len = 0; + int32_t best_of = 5; + int32_t beam_size = -1; + int32_t audio_ctx = 0; + + float word_thold = 0.01f; + float entropy_thold = 2.4f; + float logprob_thold = -1.0f; + + bool translate = false; + bool diarize = false; + bool output_txt = false; + bool output_vtt = false; + bool output_srt = false; + bool output_wts = false; + bool output_csv = false; + bool print_special = false; + bool print_colors = false; + bool print_progress = false; + bool no_timestamps = false; + bool no_prints = false; + bool use_gpu = true; + bool flash_attn = false; + bool comma_in_time = true; + + std::string language = "en"; + std::string prompt; + std::string model = "../../ggml-large.bin"; + + std::vector fname_inp = {}; + std::vector fname_out = {}; + + std::vector pcmf32 = {}; // mono-channel F32 PCM +}; + +struct whisper_print_user_data { + const whisper_params * params; + + const std::vector> * pcmf32s; +}; + +void whisper_print_segment_callback(struct whisper_context * ctx, struct whisper_state * state, int n_new, void * user_data) { + const auto & params = *((whisper_print_user_data *) user_data)->params; + const auto & pcmf32s = *((whisper_print_user_data *) user_data)->pcmf32s; + + const int n_segments = whisper_full_n_segments(ctx); + + std::string speaker = ""; + + int64_t t0; + int64_t t1; + + // print the last n_new segments + const int s0 = n_segments - n_new; + + if (s0 == 0) { + printf("\n"); + } + + for (int i = s0; i < n_segments; i++) { + if (!params.no_timestamps || params.diarize) { + t0 = whisper_full_get_segment_t0(ctx, i); + t1 = whisper_full_get_segment_t1(ctx, i); + } + + if (!params.no_timestamps) { + printf("[%s --> %s] ", to_timestamp(t0).c_str(), to_timestamp(t1).c_str()); + } + + if (params.diarize && pcmf32s.size() == 2) { + const int64_t n_samples = pcmf32s[0].size(); + + const int64_t is0 = timestamp_to_sample(t0, n_samples, WHISPER_SAMPLE_RATE); + const int64_t is1 = timestamp_to_sample(t1, n_samples, WHISPER_SAMPLE_RATE); + + double energy0 = 0.0f; + double energy1 = 0.0f; + + for (int64_t j = is0; j < is1; j++) { + energy0 += fabs(pcmf32s[0][j]); + energy1 += fabs(pcmf32s[1][j]); + } + + if (energy0 > 1.1*energy1) { + speaker = "(speaker 0)"; + } else if (energy1 > 1.1*energy0) { + speaker = "(speaker 1)"; + } else { + speaker = "(speaker ?)"; + } + + //printf("is0 = %lld, is1 = %lld, energy0 = %f, energy1 = %f, %s\n", is0, is1, energy0, energy1, speaker.c_str()); + } + + // colorful print bug + // + const char * text = whisper_full_get_segment_text(ctx, i); + printf("%s%s", speaker.c_str(), text); + + + // with timestamps or speakers: each segment on new line + if (!params.no_timestamps || params.diarize) { + printf("\n"); + } + + fflush(stdout); + } +} + +void cb_log_disable(enum ggml_log_level, const char *, void *) {} + +int run(whisper_params ¶ms, std::vector> &result) { + if (params.no_prints) { + whisper_log_set(cb_log_disable, NULL); + } + + if (params.fname_inp.empty() && params.pcmf32.empty()) { + fprintf(stderr, "error: no input files or audio buffer specified\n"); + return 2; + } + + if (params.language != "auto" && whisper_lang_id(params.language.c_str()) == -1) { + fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str()); + exit(0); + } + + // whisper init + + struct whisper_context_params cparams = whisper_context_default_params(); + cparams.use_gpu = params.use_gpu; + cparams.flash_attn = params.flash_attn; + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + if (ctx == nullptr) { + fprintf(stderr, "error: failed to initialize whisper context\n"); + return 3; + } + + // if params.pcmf32 is provided, set params.fname_inp to "buffer" + // this is simpler than further modifications in the code + if (!params.pcmf32.empty()) { + fprintf(stderr, "info: using audio buffer as input\n"); + params.fname_inp.clear(); + params.fname_inp.emplace_back("buffer"); + } + + for (int f = 0; f < (int) params.fname_inp.size(); ++f) { + const auto fname_inp = params.fname_inp[f]; + const auto fname_out = f < (int)params.fname_out.size() && !params.fname_out[f].empty() ? params.fname_out[f] : params.fname_inp[f]; + + std::vector pcmf32; // mono-channel F32 PCM + std::vector> pcmf32s; // stereo-channel F32 PCM + + // read the input audio file if params.pcmf32 is not provided + if (params.pcmf32.empty()) { + if (!::read_wav(fname_inp, pcmf32, pcmf32s, params.diarize)) { + fprintf(stderr, "error: failed to read WAV file '%s'\n", fname_inp.c_str()); + continue; + } + } else { + pcmf32 = params.pcmf32; + } + + // print system information + if (!params.no_prints) { + fprintf(stderr, "\n"); + fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", + params.n_threads*params.n_processors, std::thread::hardware_concurrency(), whisper_print_system_info()); + } + + // print some info about the processing + if (!params.no_prints) { + fprintf(stderr, "\n"); + if (!whisper_is_multilingual(ctx)) { + if (params.language != "en" || params.translate) { + params.language = "en"; + params.translate = false; + fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__); + } + } + fprintf(stderr, "%s: processing '%s' (%d samples, %.1f sec), %d threads, %d processors, lang = %s, task = %s, timestamps = %d, audio_ctx = %d ...\n", + __func__, fname_inp.c_str(), int(pcmf32.size()), float(pcmf32.size())/WHISPER_SAMPLE_RATE, + params.n_threads, params.n_processors, + params.language.c_str(), + params.translate ? "translate" : "transcribe", + params.no_timestamps ? 0 : 1, + params.audio_ctx); + + fprintf(stderr, "\n"); + } + + // run the inference + { + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + + wparams.strategy = params.beam_size > 1 ? WHISPER_SAMPLING_BEAM_SEARCH : WHISPER_SAMPLING_GREEDY; + + wparams.print_realtime = false; + wparams.print_progress = params.print_progress; + wparams.print_timestamps = !params.no_timestamps; + wparams.print_special = params.print_special; + wparams.translate = params.translate; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + wparams.n_max_text_ctx = params.max_context >= 0 ? params.max_context : wparams.n_max_text_ctx; + wparams.offset_ms = params.offset_t_ms; + wparams.duration_ms = params.duration_ms; + + wparams.token_timestamps = params.output_wts || params.max_len > 0; + wparams.thold_pt = params.word_thold; + wparams.entropy_thold = params.entropy_thold; + wparams.logprob_thold = params.logprob_thold; + wparams.max_len = params.output_wts && params.max_len == 0 ? 60 : params.max_len; + wparams.audio_ctx = params.audio_ctx; + + wparams.greedy.best_of = params.best_of; + wparams.beam_search.beam_size = params.beam_size; + + wparams.initial_prompt = params.prompt.c_str(); + + wparams.no_timestamps = params.no_timestamps; + + whisper_print_user_data user_data = { ¶ms, &pcmf32s }; + + // this callback is called on each new segment + if (!wparams.print_realtime) { + wparams.new_segment_callback = whisper_print_segment_callback; + wparams.new_segment_callback_user_data = &user_data; + } + + // example for abort mechanism + // in this example, we do not abort the processing, but we could if the flag is set to true + // the callback is called before every encoder run - if it returns false, the processing is aborted + { + static bool is_aborted = false; // NOTE: this should be atomic to avoid data race + + wparams.encoder_begin_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, void * user_data) { + bool is_aborted = *(bool*)user_data; + return !is_aborted; + }; + wparams.encoder_begin_callback_user_data = &is_aborted; + } + + if (whisper_full_parallel(ctx, wparams, pcmf32.data(), pcmf32.size(), params.n_processors) != 0) { + fprintf(stderr, "failed to process audio\n"); + return 10; + } + } + } + + const int n_segments = whisper_full_n_segments(ctx); + result.resize(n_segments); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(ctx, i); + const int64_t t0 = whisper_full_get_segment_t0(ctx, i); + const int64_t t1 = whisper_full_get_segment_t1(ctx, i); + + result[i].emplace_back(to_timestamp(t0, params.comma_in_time)); + result[i].emplace_back(to_timestamp(t1, params.comma_in_time)); + result[i].emplace_back(text); + } + + whisper_print_timings(ctx); + whisper_free(ctx); + + return 0; +} + +class Worker : public Napi::AsyncWorker { + public: + Worker(Napi::Function& callback, whisper_params params) + : Napi::AsyncWorker(callback), params(params) {} + + void Execute() override { + run(params, result); + } + + void OnOK() override { + Napi::HandleScope scope(Env()); + Napi::Object res = Napi::Array::New(Env(), result.size()); + for (uint64_t i = 0; i < result.size(); ++i) { + Napi::Object tmp = Napi::Array::New(Env(), 3); + for (uint64_t j = 0; j < 3; ++j) { + tmp[j] = Napi::String::New(Env(), result[i][j]); + } + res[i] = tmp; + } + Callback().Call({Env().Null(), res}); + } + + private: + whisper_params params; + std::vector> result; +}; + + + +Napi::Value whisper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() <= 0 || !info[0].IsObject()) { + Napi::TypeError::New(env, "object expected").ThrowAsJavaScriptException(); + } + whisper_params params; + + Napi::Object whisper_params = info[0].As(); + std::string language = whisper_params.Get("language").As(); + std::string model = whisper_params.Get("model").As(); + std::string input = whisper_params.Get("fname_inp").As(); + bool use_gpu = whisper_params.Get("use_gpu").As(); + bool flash_attn = whisper_params.Get("flash_attn").As(); + bool no_prints = whisper_params.Get("no_prints").As(); + bool no_timestamps = whisper_params.Get("no_timestamps").As(); + int32_t audio_ctx = whisper_params.Get("audio_ctx").As(); + bool comma_in_time = whisper_params.Get("comma_in_time").As(); + + Napi::Value pcmf32Value = whisper_params.Get("pcmf32"); + std::vector pcmf32_vec; + if (pcmf32Value.IsTypedArray()) { + Napi::Float32Array pcmf32 = pcmf32Value.As(); + size_t length = pcmf32.ElementLength(); + pcmf32_vec.reserve(length); + for (size_t i = 0; i < length; i++) { + pcmf32_vec.push_back(pcmf32[i]); + } + } + + params.language = language; + params.model = model; + params.fname_inp.emplace_back(input); + params.use_gpu = use_gpu; + params.flash_attn = flash_attn; + params.no_prints = no_prints; + params.no_timestamps = no_timestamps; + params.audio_ctx = audio_ctx; + params.pcmf32 = pcmf32_vec; + params.comma_in_time = comma_in_time; + + Napi::Function callback = info[1].As(); + Worker* worker = new Worker(callback, params); + worker->Queue(); + return env.Undefined(); +} + + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set( + Napi::String::New(env, "whisper"), + Napi::Function::New(env, whisper) + ); + return exports; +} + +NODE_API_MODULE(whisper, Init); diff --git a/examples/addon.node/index.js b/examples/addon.node/index.js new file mode 100644 index 0000000000000000000000000000000000000000..643ee756452de62f347eeace89a7ffbc4d8c7b3f --- /dev/null +++ b/examples/addon.node/index.js @@ -0,0 +1,50 @@ +const path = require("path"); +const { whisper } = require(path.join( + __dirname, + "../../build/Release/addon.node" +)); +const { promisify } = require("util"); + +const whisperAsync = promisify(whisper); + +const whisperParams = { + language: "en", + model: path.join(__dirname, "../../models/ggml-base.en.bin"), + fname_inp: path.join(__dirname, "../../samples/jfk.wav"), + use_gpu: true, + flash_attn: false, + no_prints: true, + comma_in_time: false, + translate: true, + no_timestamps: false, + audio_ctx: 0, +}; + +const arguments = process.argv.slice(2); +const params = Object.fromEntries( + arguments.reduce((pre, item) => { + if (item.startsWith("--")) { + const [key, value] = item.slice(2).split("="); + if (key === "audio_ctx") { + whisperParams[key] = parseInt(value); + } else { + whisperParams[key] = value; + } + return pre; + } + return pre; + }, []) +); + +for (const key in params) { + if (whisperParams.hasOwnProperty(key)) { + whisperParams[key] = params[key]; + } +} + +console.log("whisperParams =", whisperParams); + +whisperAsync(whisperParams).then((result) => { + console.log(); + console.log(result); +}); diff --git a/examples/addon.node/package.json b/examples/addon.node/package.json new file mode 100644 index 0000000000000000000000000000000000000000..50046bf1f56a6418a75732cff54c51d2decdf60d --- /dev/null +++ b/examples/addon.node/package.json @@ -0,0 +1,16 @@ +{ + "name": "addon.node", + "version": "0.0.0", + "description": "", + "main": "index.js", + "author": "Qanhe Chen", + "license": "MIT", + "scripts": { + "test": "jest" + }, + "devDependencies": { + "cmake-js": "^7.1.1", + "jest": "^29.4.0", + "node-addon-api": "^5.0.0" + } +} diff --git a/examples/bench.wasm/CMakeLists.txt b/examples/bench.wasm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f702ad75d961fc016e14b296969cee56efa9ee7c --- /dev/null +++ b/examples/bench.wasm/CMakeLists.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8961ebaf20051aa108b869a7e9af3c511fcb3e051245c1da3925a38607bf13c +size 1161 diff --git a/examples/bench.wasm/README.md b/examples/bench.wasm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4e74c5e8646238989e326f0a653ffabfd522963e --- /dev/null +++ b/examples/bench.wasm/README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:268b5825e73ee587c040ed953b2a9cd1b3f2624b79226885093e48c63539d1ad +size 502 diff --git a/examples/bench.wasm/emscripten.cpp b/examples/bench.wasm/emscripten.cpp new file mode 100644 index 0000000000000000000000000000000000000000..877238ba78c0cfd9914fc600476f19caca17a238 --- /dev/null +++ b/examples/bench.wasm/emscripten.cpp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f744445f23d9729d5bcd0716802731e328a54a99975662092170b965b9962be +size 2713 diff --git a/examples/bench.wasm/index-tmpl.html b/examples/bench.wasm/index-tmpl.html new file mode 100644 index 0000000000000000000000000000000000000000..1f556fb78a3c96a57008ee1fc69340ac46f20f32 --- /dev/null +++ b/examples/bench.wasm/index-tmpl.html @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42d67989dadfbac2c46144c43f0c33da81e4f3dc32acb9a60e667500d3b2e728 +size 12516 diff --git a/examples/bench/CMakeLists.txt b/examples/bench/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8a72ffde60390dc16395cf6aed4dbadba330c52 --- /dev/null +++ b/examples/bench/CMakeLists.txt @@ -0,0 +1,6 @@ +set(TARGET bench) +add_executable(${TARGET} bench.cpp) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE whisper ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/bench/README.md b/examples/bench/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5b42cb4d8be2ddce97784a60389e529acca3a7ad --- /dev/null +++ b/examples/bench/README.md @@ -0,0 +1,54 @@ +# bench + +A very basic tool for benchmarking the inference performance on your device. The tool simply runs the Encoder part of +the transformer on some random audio data and records the execution time. This way we can have an objective comparison +of the performance of the model for various setups. + +Benchmark results are tracked in the following Github issue: https://github.com/ggerganov/whisper.cpp/issues/89 + +```bash +# build the bench tool +$ make bench + +# run it on the small.en model using 4 threads +$ ./bench -m ./models/ggml-small.en.bin -t 4 + +whisper_model_load: loading model from './models/ggml-small.en.bin' +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 768 +whisper_model_load: n_audio_head = 12 +whisper_model_load: n_audio_layer = 12 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 768 +whisper_model_load: n_text_head = 12 +whisper_model_load: n_text_layer = 12 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 3 +whisper_model_load: mem_required = 1048.00 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: ggml ctx size = 533.05 MB +whisper_model_load: memory size = 68.48 MB +whisper_model_load: model size = 464.44 MB + +whisper_print_timings: load time = 240.82 ms +whisper_print_timings: mel time = 0.00 ms +whisper_print_timings: sample time = 0.00 ms +whisper_print_timings: encode time = 1062.21 ms / 88.52 ms per layer +whisper_print_timings: decode time = 0.00 ms / 0.00 ms per layer +whisper_print_timings: total time = 1303.04 ms + +system_info: n_threads = 4 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +If you wish, you can submit these results here: + + https://github.com/ggerganov/whisper.cpp/issues/89 + +Please include the following information: + + - CPU model + - Operating system + - Compiler + +``` diff --git a/examples/bench/bench.cpp b/examples/bench/bench.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d19c8ac54af62940abdd56fb3851cbafe8c03339 --- /dev/null +++ b/examples/bench/bench.cpp @@ -0,0 +1,175 @@ +#include "whisper.h" + +#include +#include +#include +#include + +// command-line parameters +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t what = 0; // what to benchmark: 0 - whisper encoder, 1 - memcpy, 2 - ggml_mul_mat + + std::string model = "models/ggml-base.en.bin"; + + bool use_gpu = true; + bool flash_attn = false; +}; + +void whisper_print_usage(int argc, char ** argv, const whisper_params & params); + +static bool whisper_params_parse(int argc, char ** argv, whisper_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") { + whisper_print_usage(argc, argv, params); + exit(0); + } + else if (arg == "-t" || arg == "--threads") { params.n_threads = std::stoi(argv[++i]); } + else if (arg == "-m" || arg == "--model") { params.model = argv[++i]; } + else if (arg == "-w" || arg == "--what") { params.what = atoi(argv[++i]); } + else if (arg == "-ng" || arg == "--no-gpu") { params.use_gpu = false; } + else if (arg == "-fa" || arg == "--flash-attn") { params.flash_attn = true; } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help [default] show this help message and exit\n"); + fprintf(stderr, " -t N, --threads N [%-7d] number of threads to use during computation\n", params.n_threads); + fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str()); + fprintf(stderr, " -w N, --what N [%-7d] what to benchmark:\n", params.what); + fprintf(stderr, " -ng, --no-gpu [%-7s] disable GPU\n", params.use_gpu ? "false" : "true"); + fprintf(stderr, " -fa, --flash-attn [%-7s] enable flash attention\n", params.flash_attn ? "true" : "false"); + fprintf(stderr, " %-7s 0 - whisper\n", ""); + fprintf(stderr, " %-7s 1 - memcpy\n", ""); + fprintf(stderr, " %-7s 2 - ggml_mul_mat\n", ""); + fprintf(stderr, "\n"); +} + +static int whisper_bench_full(const whisper_params & params) { + // whisper init + + struct whisper_context_params cparams = whisper_context_default_params(); + + cparams.use_gpu = params.use_gpu; + cparams.flash_attn = params.flash_attn; + + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + { + fprintf(stderr, "\n"); + fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", params.n_threads, std::thread::hardware_concurrency(), whisper_print_system_info()); + } + + if (ctx == nullptr) { + fprintf(stderr, "error: failed to initialize whisper context\n"); + return 2; + } + + const int n_mels = whisper_model_n_mels(ctx); + + if (int ret = whisper_set_mel(ctx, nullptr, 0, n_mels)) { + fprintf(stderr, "error: failed to set mel: %d\n", ret); + return 3; + } + // heat encoder + if (int ret = whisper_encode(ctx, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to encode: %d\n", ret); + return 4; + } + + whisper_token tokens[512]; + memset(tokens, 0, sizeof(tokens)); + + // prompt heat + if (int ret = whisper_decode(ctx, tokens, 256, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + + // text-generation heat + if (int ret = whisper_decode(ctx, tokens, 1, 256, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + + whisper_reset_timings(ctx); + + // actual run + if (int ret = whisper_encode(ctx, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to encode: %d\n", ret); + return 4; + } + + // text-generation + for (int i = 0; i < 256; i++) { + if (int ret = whisper_decode(ctx, tokens, 1, i, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + // batched decoding + for (int i = 0; i < 64; i++) { + if (int ret = whisper_decode(ctx, tokens, 5, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + // prompt processing + for (int i = 0; i < 16; i++) { + if (int ret = whisper_decode(ctx, tokens, 256, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + whisper_print_timings(ctx); + whisper_free(ctx); + + fprintf(stderr, "\n"); + fprintf(stderr, "If you wish, you can submit these results here:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " https://github.com/ggerganov/whisper.cpp/issues/89\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Please include the following information:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " - CPU model\n"); + fprintf(stderr, " - Operating system\n"); + fprintf(stderr, " - Compiler\n"); + fprintf(stderr, "\n"); + + return 0; +} + +int main(int argc, char ** argv) { + whisper_params params; + + if (whisper_params_parse(argc, argv, params) == false) { + return 1; + } + + int ret = -1; + + switch (params.what) { + case 0: ret = whisper_bench_full(params); break; + case 1: ret = whisper_bench_memcpy(params.n_threads); break; + case 2: ret = whisper_bench_ggml_mul_mat(params.n_threads); break; + default: fprintf(stderr, "error: unknown benchmark: %d\n", params.what); break; + } + + return ret; +} diff --git a/examples/command.wasm/CMakeLists.txt b/examples/command.wasm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fa99ef1a801c5dcfbcce29a474acbb19a31cd7b --- /dev/null +++ b/examples/command.wasm/CMakeLists.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54a75ef24fb90c8753d2b79dca848f42c014cfd35a79257c7eabca6f568e97b8 +size 1181 diff --git a/examples/command.wasm/README.md b/examples/command.wasm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8316dea93f0523dbcc002684d3e03c9243a1803f --- /dev/null +++ b/examples/command.wasm/README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:297c3037c11c2d963ee6b6179b06db504283186bb54298fbcb602d9a31b168b0 +size 585 diff --git a/examples/command.wasm/emscripten.cpp b/examples/command.wasm/emscripten.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ecbf38718ddca8a412e60373a7aa5006f989aa2 --- /dev/null +++ b/examples/command.wasm/emscripten.cpp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4aab4249ef14b620e0ab1839a90f3f5878132ae897ac9756ad05c647d0298952 +size 10458 diff --git a/examples/command.wasm/index-tmpl.html b/examples/command.wasm/index-tmpl.html new file mode 100644 index 0000000000000000000000000000000000000000..ceff187be8839c41397fead8190c3f499e0e0be6 --- /dev/null +++ b/examples/command.wasm/index-tmpl.html @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f7f4d3653d78717e623583abe746c591bbc7b2e39381c78e6b68158d4ccb0b7 +size 16219 diff --git a/examples/command/CMakeLists.txt b/examples/command/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..40f278c1813326849c827f76e7b885d895ebdeb6 --- /dev/null +++ b/examples/command/CMakeLists.txt @@ -0,0 +1,9 @@ +if (WHISPER_SDL2) + # command + set(TARGET command) + add_executable(${TARGET} command.cpp) + + include(DefaultTargetOptions) + + target_link_libraries(${TARGET} PRIVATE common common-sdl whisper ${CMAKE_THREAD_LIBS_INIT}) +endif () diff --git a/examples/command/README.md b/examples/command/README.md new file mode 100644 index 0000000000000000000000000000000000000000..46b14e932776b9de6071680b1be280e8d8bc63bf --- /dev/null +++ b/examples/command/README.md @@ -0,0 +1,51 @@ +# command + +This is a basic Voice Assistant example that accepts voice commands from the microphone. +More info is available in [issue #171](https://github.com/ggerganov/whisper.cpp/issues/171). + +```bash +# Run with default arguments and small model +./command -m ./models/ggml-small.en.bin -t 8 + +# On Raspberry Pi, use tiny or base models + "-ac 768" for better performance +./command -m ./models/ggml-tiny.en.bin -ac 768 -t 3 -c 0 +``` + +https://user-images.githubusercontent.com/1991296/204038393-2f846eae-c255-4099-a76d-5735c25c49da.mp4 + +Web version: [examples/command.wasm](/examples/command.wasm) + +## Guided mode + +"Guided mode" allows you to specify a list of commands (i.e. strings) and the transcription will be guided to classify your command into one from the list. This can be useful in situations where a device is listening only for a small subset of commands. + +Initial tests show that this approach might be extremely efficient in terms of performance, since it integrates very well with the "partial Encoder" idea from #137. + +```bash +# Run in guided mode, the list of allowed commands is in commands.txt +./command -m ./models/ggml-base.en.bin -cmd ./examples/command/commands.txt + +# On Raspberry Pi, in guided mode you can use "-ac 128" for extra performance +./command -m ./models/ggml-tiny.en.bin -cmd ./examples/command/commands.txt -ac 128 -t 3 -c 0 +``` + +https://user-images.githubusercontent.com/1991296/207435352-8fc4ed3f-bde5-4555-9b8b-aeeb76bee969.mp4 + + +## Building + +The `command` tool depends on SDL2 library to capture audio from the microphone. You can build it like this: + +```bash +# Install SDL2 +# On Debian based linux distributions: +sudo apt-get install libsdl2-dev + +# On Fedora Linux: +sudo dnf install SDL2 SDL2-devel + +# Install SDL2 on Mac OS +brew install sdl2 + +make command +``` diff --git a/examples/command/command.cpp b/examples/command/command.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11ed9ed6bd3ce8e02855fd21e0c24e7330a873d9 --- /dev/null +++ b/examples/command/command.cpp @@ -0,0 +1,777 @@ +// Voice assistant example +// +// Speak short text commands to the microphone. +// This program will detect your voice command and convert them to text. +// +// ref: https://github.com/ggerganov/whisper.cpp/issues/171 +// + +#include "common-sdl.h" +#include "common.h" +#include "whisper.h" +#include "grammar-parser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// command-line parameters +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t prompt_ms = 5000; + int32_t command_ms = 8000; + int32_t capture_id = -1; + int32_t max_tokens = 32; + int32_t audio_ctx = 0; + + float vad_thold = 0.6f; + float freq_thold = 100.0f; + + float grammar_penalty = 100.0f; + + grammar_parser::parse_state grammar_parsed; + + bool translate = false; + bool print_special = false; + bool print_energy = false; + bool no_timestamps = true; + bool use_gpu = true; + bool flash_attn = false; + + std::string language = "en"; + std::string model = "models/ggml-base.en.bin"; + std::string fname_out; + std::string commands; + std::string prompt; + std::string context; + std::string grammar; + + // A regular expression that matches tokens to suppress + std::string suppress_regex; +}; + +void whisper_print_usage(int argc, char ** argv, const whisper_params & params); + +static bool whisper_params_parse(int argc, char ** argv, whisper_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") { + whisper_print_usage(argc, argv, params); + exit(0); + } + else if (arg == "-t" || arg == "--threads") { params.n_threads = std::stoi(argv[++i]); } + else if (arg == "-pms" || arg == "--prompt-ms") { params.prompt_ms = std::stoi(argv[++i]); } + else if (arg == "-cms" || arg == "--command-ms") { params.command_ms = std::stoi(argv[++i]); } + else if (arg == "-c" || arg == "--capture") { params.capture_id = std::stoi(argv[++i]); } + else if (arg == "-mt" || arg == "--max-tokens") { params.max_tokens = std::stoi(argv[++i]); } + else if (arg == "-ac" || arg == "--audio-ctx") { params.audio_ctx = std::stoi(argv[++i]); } + else if (arg == "-vth" || arg == "--vad-thold") { params.vad_thold = std::stof(argv[++i]); } + else if (arg == "-fth" || arg == "--freq-thold") { params.freq_thold = std::stof(argv[++i]); } + else if (arg == "-tr" || arg == "--translate") { params.translate = true; } + else if (arg == "-ps" || arg == "--print-special") { params.print_special = true; } + else if (arg == "-pe" || arg == "--print-energy") { params.print_energy = true; } + else if (arg == "-ng" || arg == "--no-gpu") { params.use_gpu = false; } + else if (arg == "-fa" || arg == "--flash-attn") { params.flash_attn = true; } + else if (arg == "-l" || arg == "--language") { params.language = argv[++i]; } + else if (arg == "-m" || arg == "--model") { params.model = argv[++i]; } + else if (arg == "-f" || arg == "--file") { params.fname_out = argv[++i]; } + else if (arg == "-cmd" || arg == "--commands") { params.commands = argv[++i]; } + else if (arg == "-p" || arg == "--prompt") { params.prompt = argv[++i]; } + else if (arg == "-ctx" || arg == "--context") { params.context = argv[++i]; } + else if ( arg == "--grammar") { params.grammar = argv[++i]; } + else if ( arg == "--grammar-penalty") { params.grammar_penalty = std::stof(argv[++i]); } + else if ( arg == "--suppress-regex") { params.suppress_regex = argv[++i]; } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help [default] show this help message and exit\n"); + fprintf(stderr, " -t N, --threads N [%-7d] number of threads to use during computation\n", params.n_threads); + fprintf(stderr, " -pms N, --prompt-ms N [%-7d] prompt duration in milliseconds\n", params.prompt_ms); + fprintf(stderr, " -cms N, --command-ms N [%-7d] command duration in milliseconds\n", params.command_ms); + fprintf(stderr, " -c ID, --capture ID [%-7d] capture device ID\n", params.capture_id); + fprintf(stderr, " -mt N, --max-tokens N [%-7d] maximum number of tokens per audio chunk\n", params.max_tokens); + fprintf(stderr, " -ac N, --audio-ctx N [%-7d] audio context size (0 - all)\n", params.audio_ctx); + fprintf(stderr, " -vth N, --vad-thold N [%-7.2f] voice activity detection threshold\n", params.vad_thold); + fprintf(stderr, " -fth N, --freq-thold N [%-7.2f] high-pass frequency cutoff\n", params.freq_thold); + fprintf(stderr, " -tr, --translate [%-7s] translate from source language to english\n", params.translate ? "true" : "false"); + fprintf(stderr, " -ps, --print-special [%-7s] print special tokens\n", params.print_special ? "true" : "false"); + fprintf(stderr, " -pe, --print-energy [%-7s] print sound energy (for debugging)\n", params.print_energy ? "true" : "false"); + fprintf(stderr, " -ng, --no-gpu [%-7s] disable GPU\n", params.use_gpu ? "false" : "true"); + fprintf(stderr, " -fa, --flash-attn [%-7s] flash attention\n", params.flash_attn ? "true" : "false"); + fprintf(stderr, " -l LANG, --language LANG [%-7s] spoken language\n", params.language.c_str()); + fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str()); + fprintf(stderr, " -f FNAME, --file FNAME [%-7s] text output file name\n", params.fname_out.c_str()); + fprintf(stderr, " -cmd FNAME, --commands FNAME [%-7s] text file with allowed commands\n", params.commands.c_str()); + fprintf(stderr, " -p, --prompt [%-7s] the required activation prompt\n", params.prompt.c_str()); + fprintf(stderr, " -ctx, --context [%-7s] sample text to help the transcription\n", params.context.c_str()); + fprintf(stderr, " --grammar GRAMMAR [%-7s] GBNF grammar to guide decoding\n", params.grammar.c_str()); + fprintf(stderr, " --grammar-penalty N [%-7.1f] scales down logits of nongrammar tokens\n", params.grammar_penalty); + fprintf(stderr, " --suppress-regex REGEX [%-7s] regular expression matching tokens to suppress\n", params.suppress_regex.c_str()); + fprintf(stderr, "\n"); +} + +static std::string transcribe( + whisper_context * ctx, + const whisper_params & params, + const std::vector & pcmf32, + const std::string & grammar_rule, + float & logprob_min, + float & logprob_sum, + int & n_tokens, + int64_t & t_ms) { + const auto t_start = std::chrono::high_resolution_clock::now(); + + logprob_min = 0.0f; + logprob_sum = 0.0f; + n_tokens = 0; + t_ms = 0; + + //whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_BEAM_SEARCH); + + wparams.print_progress = false; + wparams.print_special = params.print_special; + wparams.print_realtime = false; + wparams.print_timestamps = !params.no_timestamps; + wparams.translate = params.translate; + wparams.no_context = true; + wparams.no_timestamps = params.no_timestamps; + wparams.single_segment = true; + wparams.max_tokens = params.max_tokens; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + + wparams.audio_ctx = params.audio_ctx; + + wparams.temperature = 0.4f; + wparams.temperature_inc = 1.0f; + wparams.greedy.best_of = 5; + + wparams.beam_search.beam_size = 5; + + wparams.initial_prompt = params.context.data(); + + wparams.suppress_regex = params.suppress_regex.c_str(); + + const auto & grammar_parsed = params.grammar_parsed; + auto grammar_rules = grammar_parsed.c_rules(); + + if (!params.grammar_parsed.rules.empty() && !grammar_rule.empty()) { + if (grammar_parsed.symbol_ids.find(grammar_rule) == grammar_parsed.symbol_ids.end()) { + fprintf(stderr, "%s: warning: grammar rule '%s' not found - skipping grammar sampling\n", __func__, grammar_rule.c_str()); + } else { + wparams.grammar_rules = grammar_rules.data(); + wparams.n_grammar_rules = grammar_rules.size(); + wparams.i_start_rule = grammar_parsed.symbol_ids.at(grammar_rule); + wparams.grammar_penalty = params.grammar_penalty; + } + } + + if (whisper_full(ctx, wparams, pcmf32.data(), pcmf32.size()) != 0) { + return ""; + } + + std::string result; + + const int n_segments = whisper_full_n_segments(ctx); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(ctx, i); + + result += text; + + const int n = whisper_full_n_tokens(ctx, i); + for (int j = 0; j < n; ++j) { + const auto token = whisper_full_get_token_data(ctx, i, j); + + if(token.plog > 0.0f) exit(0); + logprob_min = std::min(logprob_min, token.plog); + logprob_sum += token.plog; + ++n_tokens; + } + } + + const auto t_end = std::chrono::high_resolution_clock::now(); + t_ms = std::chrono::duration_cast(t_end - t_start).count(); + + return result; +} + +static std::vector read_allowed_commands(const std::string & fname) { + std::vector allowed_commands; + + std::ifstream ifs(fname); + if (!ifs.is_open()) { + return allowed_commands; + } + + std::string line; + while (std::getline(ifs, line)) { + line = ::trim(line); + if (line.empty()) { + continue; + } + + std::transform(line.begin(), line.end(),line.begin(), ::tolower); + allowed_commands.push_back(std::move(line)); + } + + return allowed_commands; +} + +static std::vector get_words(const std::string &txt) { + std::vector words; + + std::istringstream iss(txt); + std::string word; + while (iss >> word) { + words.push_back(word); + } + + return words; +} + +// command-list mode +// guide the transcription to match the most likely command from a provided list +static int process_command_list(struct whisper_context * ctx, audio_async &audio, const whisper_params ¶ms) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: guided mode\n", __func__); + + std::vector allowed_commands = read_allowed_commands(params.commands); + + if (allowed_commands.empty()) { + fprintf(stderr, "%s: error: failed to read allowed commands from '%s'\n", __func__, params.commands.c_str()); + return 2; + } + + int max_len = 0; + + std::vector> allowed_tokens; + + for (const auto & cmd : allowed_commands) { + whisper_token tokens[1024]; + allowed_tokens.emplace_back(); + + for (int l = 0; l < (int) cmd.size(); ++l) { + // NOTE: very important to add the whitespace ! + // the reason is that the first decoded token starts with a whitespace too! + std::string ss = std::string(" ") + cmd.substr(0, l + 1); + + const int n = whisper_tokenize(ctx, ss.c_str(), tokens, 1024); + if (n < 0) { + fprintf(stderr, "%s: error: failed to tokenize command '%s'\n", __func__, cmd.c_str()); + return 3; + } + + if (n == 1) { + allowed_tokens.back().push_back(tokens[0]); + } + } + + max_len = std::max(max_len, (int) cmd.size()); + } + + fprintf(stderr, "%s: allowed commands [ tokens ]:\n", __func__); + fprintf(stderr, "\n"); + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + fprintf(stderr, " - \033[1m%-*s\033[0m = [", max_len, allowed_commands[i].c_str()); + for (const auto & token : allowed_tokens[i]) { + fprintf(stderr, " %5d", token); + } + fprintf(stderr, " ]\n"); + } + + std::string k_prompt = "select one from the available words: "; + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + if (i > 0) { + k_prompt += ", "; + } + k_prompt += allowed_commands[i]; + } + k_prompt += ". selected word: "; + + // tokenize prompt + std::vector k_tokens; + { + k_tokens.resize(1024); + const int n = whisper_tokenize(ctx, k_prompt.c_str(), k_tokens.data(), 1024); + if (n < 0) { + fprintf(stderr, "%s: error: failed to tokenize prompt '%s'\n", __func__, k_prompt.c_str()); + return 4; + } + k_tokens.resize(n); + } + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: prompt: '%s'\n", __func__, k_prompt.c_str()); + fprintf(stderr, "%s: tokens: [", __func__); + for (const auto & token : k_tokens) { + fprintf(stderr, " %d", token); + } + fprintf(stderr, " ]\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: listening for a command ...\n", __func__); + fprintf(stderr, "\n"); + + bool is_running = true; + + std::vector pcmf32_cur; + std::vector pcmf32_prompt; + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + const auto t_start = std::chrono::high_resolution_clock::now(); + + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + + wparams.print_progress = false; + wparams.print_special = params.print_special; + wparams.print_realtime = false; + wparams.print_timestamps = !params.no_timestamps; + wparams.translate = params.translate; + wparams.no_context = true; + wparams.single_segment = true; + wparams.max_tokens = 1; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + + wparams.audio_ctx = params.audio_ctx; + + wparams.prompt_tokens = k_tokens.data(); + wparams.prompt_n_tokens = k_tokens.size(); + + // run the transformer and a single decoding pass + if (whisper_full(ctx, wparams, pcmf32_cur.data(), pcmf32_cur.size()) != 0) { + fprintf(stderr, "%s: ERROR: whisper_full() failed\n", __func__); + break; + } + + // estimate command probability + // NOTE: not optimal + { + const auto * logits = whisper_get_logits(ctx); + + std::vector probs(whisper_n_vocab(ctx), 0.0f); + + // compute probs from logits via softmax + { + float max = -1e9; + for (int i = 0; i < (int) probs.size(); ++i) { + max = std::max(max, logits[i]); + } + + float sum = 0.0f; + for (int i = 0; i < (int) probs.size(); ++i) { + probs[i] = expf(logits[i] - max); + sum += probs[i]; + } + + for (int i = 0; i < (int) probs.size(); ++i) { + probs[i] /= sum; + } + } + + std::vector> probs_id; + + double psum = 0.0; + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + probs_id.emplace_back(probs[allowed_tokens[i][0]], i); + for (int j = 1; j < (int) allowed_tokens[i].size(); ++j) { + probs_id.back().first += probs[allowed_tokens[i][j]]; + } + probs_id.back().first /= allowed_tokens[i].size(); + psum += probs_id.back().first; + } + + // normalize + for (auto & p : probs_id) { + p.first /= psum; + } + + // sort descending + { + using pair_type = decltype(probs_id)::value_type; + std::sort(probs_id.begin(), probs_id.end(), [](const pair_type & a, const pair_type & b) { + return a.first > b.first; + }); + } + + // print the commands and the respective probabilities + { + fprintf(stdout, "\n"); + for (const auto & cmd : probs_id) { + fprintf(stdout, "%s: %s%-*s%s = %f | ", __func__, "\033[1m", max_len, allowed_commands[cmd.second].c_str(), "\033[0m", cmd.first); + for (int token : allowed_tokens[cmd.second]) { + fprintf(stdout, "'%4s' %f ", whisper_token_to_str(ctx, token), probs[token]); + } + fprintf(stdout, "\n"); + } + } + + // best command + { + const auto t_end = std::chrono::high_resolution_clock::now(); + + const float prob = probs_id[0].first; + const int index = probs_id[0].second; + + fprintf(stdout, "\n"); + fprintf(stdout, "%s: detected command: %s%s%s | p = %f | t = %d ms\n", __func__, + "\033[1m", allowed_commands[index].c_str(), "\033[0m", prob, + (int) std::chrono::duration_cast(t_end - t_start).count()); + fprintf(stdout, "\n"); + } + } + + audio.clear(); + } + } + + return 0; +} + +// always-prompt mode +// transcribe the voice into text after valid prompt +static int always_prompt_transcription(struct whisper_context * ctx, audio_async & audio, const whisper_params & params) { + bool is_running = true; + bool ask_prompt = true; + + float logprob_min = 0.0f; + float logprob_sum = 0.0f; + int n_tokens = 0; + + std::vector pcmf32_cur; + + const std::string k_prompt = params.prompt; + + const int k_prompt_length = get_words(k_prompt).size(); + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: always-prompt mode\n", __func__); + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if (ask_prompt) { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: The prompt is: '%s%s%s'\n", __func__, "\033[1m", k_prompt.c_str(), "\033[0m"); + fprintf(stdout, "\n"); + + ask_prompt = false; + } + + { + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + int64_t t_ms = 0; + + // detect the commands + audio.get(params.command_ms, pcmf32_cur); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "", logprob_min, logprob_sum, n_tokens, t_ms)); + + const auto words = get_words(txt); + + std::string prompt; + std::string command; + + for (int i = 0; i < (int) words.size(); ++i) { + if (i < k_prompt_length) { + prompt += words[i] + " "; + } else { + command += words[i] + " "; + } + } + + const float sim = similarity(prompt, k_prompt); + + //debug + //fprintf(stdout, "command size: %i\n", command_length); + + if ((sim > 0.7f) && (command.size() > 0)) { + fprintf(stdout, "%s: Command '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", command.c_str(), "\033[0m", (int) t_ms); + } + + fprintf(stdout, "\n"); + + audio.clear(); + } + } + } + + return 0; +} + +// general-purpose mode +// freely transcribe the voice into text +static int process_general_transcription(struct whisper_context * ctx, audio_async & audio, const whisper_params & params) { + bool is_running = true; + bool have_prompt = false; + bool ask_prompt = true; + + float logprob_min0 = 0.0f; + float logprob_min = 0.0f; + + float logprob_sum0 = 0.0f; + float logprob_sum = 0.0f; + + int n_tokens0 = 0; + int n_tokens = 0; + + std::vector pcmf32_cur; + std::vector pcmf32_prompt; + + std::string k_prompt = "Ok Whisper, start listening for commands."; + if (!params.prompt.empty()) { + k_prompt = params.prompt; + } + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: general-purpose mode\n", __func__); + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if (ask_prompt) { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: Say the following phrase: '%s%s%s'\n", __func__, "\033[1m", k_prompt.c_str(), "\033[0m"); + fprintf(stdout, "\n"); + + ask_prompt = false; + } + + { + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + int64_t t_ms = 0; + + if (!have_prompt) { + // wait for activation phrase + audio.get(params.prompt_ms, pcmf32_cur); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "prompt", logprob_min0, logprob_sum0, n_tokens0, t_ms)); + + const float p = 100.0f * std::exp(logprob_min0); + + fprintf(stdout, "%s: Heard '%s%s%s', (t = %d ms, p = %.2f%%)\n", __func__, "\033[1m", txt.c_str(), "\033[0m", (int) t_ms, p); + + const float sim = similarity(txt, k_prompt); + + if (txt.length() < 0.8*k_prompt.length() || txt.length() > 1.2*k_prompt.length() || sim < 0.8f) { + fprintf(stdout, "%s: WARNING: prompt not recognized, try again\n", __func__); + ask_prompt = true; + } else { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: The prompt has been recognized!\n", __func__); + fprintf(stdout, "%s: Waiting for voice commands ...\n", __func__); + fprintf(stdout, "\n"); + + // save the audio for the prompt + pcmf32_prompt = pcmf32_cur; + have_prompt = true; + } + } else { + // we have heard the activation phrase, now detect the commands + audio.get(params.command_ms, pcmf32_cur); + + //printf("len prompt: %.4f\n", pcmf32_prompt.size() / (float) WHISPER_SAMPLE_RATE); + //printf("len command: %.4f\n", pcmf32_cur.size() / (float) WHISPER_SAMPLE_RATE); + + // prepend 3 second of silence + pcmf32_cur.insert(pcmf32_cur.begin(), 3.0f*WHISPER_SAMPLE_RATE, 0.0f); + + // prepend the prompt audio + pcmf32_cur.insert(pcmf32_cur.begin(), pcmf32_prompt.begin(), pcmf32_prompt.end()); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "root", logprob_min, logprob_sum, n_tokens, t_ms)); + + //const float p = 100.0f * std::exp((logprob - logprob0) / (n_tokens - n_tokens0)); + const float p = 100.0f * std::exp(logprob_min); + + //fprintf(stdout, "%s: heard '%s'\n", __func__, txt.c_str()); + + // find the prompt in the text + float best_sim = 0.0f; + size_t best_len = 0; + for (size_t n = 0.8*k_prompt.size(); n <= 1.2*k_prompt.size(); ++n) { + if (n >= txt.size()) { + break; + } + + const auto prompt = txt.substr(0, n); + + const float sim = similarity(prompt, k_prompt); + + //fprintf(stderr, "%s: prompt = '%s', sim = %f\n", __func__, prompt.c_str(), sim); + + if (sim > best_sim) { + best_sim = sim; + best_len = n; + } + } + + fprintf(stdout, "%s: DEBUG: txt = '%s', prob = %.2f%%\n", __func__, txt.c_str(), p); + if (best_len == 0) { + fprintf(stdout, "%s: WARNING: command not recognized, try again\n", __func__); + } else { + // cut the prompt from the decoded text + const std::string command = ::trim(txt.substr(best_len)); + + fprintf(stdout, "%s: Command '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", command.c_str(), "\033[0m", (int) t_ms); + } + + fprintf(stdout, "\n"); + } + + audio.clear(); + } + } + } + + return 0; +} + +int main(int argc, char ** argv) { + whisper_params params; + + if (whisper_params_parse(argc, argv, params) == false) { + return 1; + } + + if (whisper_lang_id(params.language.c_str()) == -1) { + fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + + // whisper init + + struct whisper_context_params cparams = whisper_context_default_params(); + + cparams.use_gpu = params.use_gpu; + cparams.flash_attn = params.flash_attn; + + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + // print some info about the processing + { + fprintf(stderr, "\n"); + if (!whisper_is_multilingual(ctx)) { + if (params.language != "en" || params.translate) { + params.language = "en"; + params.translate = false; + fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__); + } + } + fprintf(stderr, "%s: processing, %d threads, lang = %s, task = %s, timestamps = %d ...\n", + __func__, + params.n_threads, + params.language.c_str(), + params.translate ? "translate" : "transcribe", + params.no_timestamps ? 0 : 1); + + fprintf(stderr, "\n"); + } + + // init audio + + audio_async audio(30*1000); + if (!audio.init(params.capture_id, WHISPER_SAMPLE_RATE)) { + fprintf(stderr, "%s: audio.init() failed!\n", __func__); + return 1; + } + + audio.resume(); + + // wait for 1 second to avoid any buffered noise + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + audio.clear(); + + int ret_val = 0; + + if (!params.grammar.empty()) { + auto & grammar = params.grammar_parsed; + if (is_file_exist(params.grammar.c_str())) { + // read grammar from file + std::ifstream ifs(params.grammar.c_str()); + const std::string txt = std::string((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + grammar = grammar_parser::parse(txt.c_str()); + } else { + // read grammar from string + grammar = grammar_parser::parse(params.grammar.c_str()); + } + + // will be empty (default) if there are parse errors + if (grammar.rules.empty()) { + ret_val = 1; + } else { + fprintf(stderr, "%s: grammar:\n", __func__); + grammar_parser::print_grammar(stderr, grammar); + fprintf(stderr, "\n"); + } + } + + if (ret_val == 0) { + if (!params.commands.empty()) { + ret_val = process_command_list(ctx, audio, params); + } else if (!params.prompt.empty() && params.grammar_parsed.rules.empty()) { + ret_val = always_prompt_transcription(ctx, audio, params); + } else { + ret_val = process_general_transcription(ctx, audio, params); + } + } + + audio.pause(); + + whisper_print_timings(ctx); + whisper_free(ctx); + + return ret_val; +} diff --git a/examples/command/commands.txt b/examples/command/commands.txt new file mode 100644 index 0000000000000000000000000000000000000000..2653de65215764ace76ebc9c7a806845f5eeeff6 --- /dev/null +++ b/examples/command/commands.txt @@ -0,0 +1,9 @@ +enable +disable +cat +dog +apple +red +blue +green +lightblue diff --git a/examples/common-ggml.cpp b/examples/common-ggml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3f2c12f7ce679e8e5022df1e9b18196307ee813 --- /dev/null +++ b/examples/common-ggml.cpp @@ -0,0 +1,242 @@ +#include "common-ggml.h" + +#include +#include + +static const std::map GGML_FTYPE_MAP = { + {"q4_0", GGML_FTYPE_MOSTLY_Q4_0}, + {"q4_1", GGML_FTYPE_MOSTLY_Q4_1}, + {"q5_0", GGML_FTYPE_MOSTLY_Q5_0}, + {"q5_1", GGML_FTYPE_MOSTLY_Q5_1}, + {"q8_0", GGML_FTYPE_MOSTLY_Q8_0}, + {"q2_k", GGML_FTYPE_MOSTLY_Q2_K}, + {"q3_k", GGML_FTYPE_MOSTLY_Q3_K}, + {"q4_k", GGML_FTYPE_MOSTLY_Q4_K}, + {"q5_k", GGML_FTYPE_MOSTLY_Q5_K}, + {"q6_k", GGML_FTYPE_MOSTLY_Q6_K}, +}; + +void ggml_print_ftypes(FILE * fp) { + for (auto it = GGML_FTYPE_MAP.begin(); it != GGML_FTYPE_MAP.end(); it++) { + fprintf(fp, " type = \"%s\" or %d\n", it->first.c_str(), it->second); + } +} + +enum ggml_ftype ggml_parse_ftype(const char * str) { + enum ggml_ftype ftype; + if (str[0] == 'q') { + const auto it = GGML_FTYPE_MAP.find(str); + if (it == GGML_FTYPE_MAP.end()) { + fprintf(stderr, "%s: unknown ftype '%s'\n", __func__, str); + return GGML_FTYPE_UNKNOWN; + } + ftype = it->second; + } else { + ftype = (enum ggml_ftype) atoi(str); + } + + return ftype; +} + +bool ggml_common_quantize_0( + std::ifstream & finp, + std::ofstream & fout, + const ggml_ftype ftype, + const std::vector & to_quant, + const std::vector & to_skip) { + + ggml_type qtype = GGML_TYPE_F32; + + switch (ftype) { + case GGML_FTYPE_MOSTLY_Q4_0: qtype = GGML_TYPE_Q4_0; break; + case GGML_FTYPE_MOSTLY_Q4_1: qtype = GGML_TYPE_Q4_1; break; + case GGML_FTYPE_MOSTLY_Q5_0: qtype = GGML_TYPE_Q5_0; break; + case GGML_FTYPE_MOSTLY_Q5_1: qtype = GGML_TYPE_Q5_1; break; + case GGML_FTYPE_MOSTLY_Q8_0: qtype = GGML_TYPE_Q8_0; break; + case GGML_FTYPE_MOSTLY_Q2_K: qtype = GGML_TYPE_Q2_K; break; + case GGML_FTYPE_MOSTLY_Q3_K: qtype = GGML_TYPE_Q3_K; break; + case GGML_FTYPE_MOSTLY_Q4_K: qtype = GGML_TYPE_Q4_K; break; + case GGML_FTYPE_MOSTLY_Q5_K: qtype = GGML_TYPE_Q5_K; break; + case GGML_FTYPE_MOSTLY_Q6_K: qtype = GGML_TYPE_Q6_K; break; + case GGML_FTYPE_UNKNOWN: + case GGML_FTYPE_ALL_F32: + case GGML_FTYPE_MOSTLY_F16: + case GGML_FTYPE_MOSTLY_Q4_1_SOME_F16: + case GGML_FTYPE_MOSTLY_IQ2_XXS: + case GGML_FTYPE_MOSTLY_IQ2_XS: + case GGML_FTYPE_MOSTLY_IQ2_S: + case GGML_FTYPE_MOSTLY_IQ3_XXS: + case GGML_FTYPE_MOSTLY_IQ3_S: + case GGML_FTYPE_MOSTLY_IQ1_S: + case GGML_FTYPE_MOSTLY_IQ4_NL: + case GGML_FTYPE_MOSTLY_IQ4_XS: + case GGML_FTYPE_MOSTLY_IQ1_M: + case GGML_FTYPE_MOSTLY_BF16: + case GGML_FTYPE_MOSTLY_Q4_0_4_4: + case GGML_FTYPE_MOSTLY_Q4_0_4_8: + case GGML_FTYPE_MOSTLY_Q4_0_8_8: + { + fprintf(stderr, "%s: invalid model type %d\n", __func__, ftype); + return false; + } + }; + + if (!ggml_is_quantized(qtype)) { + fprintf(stderr, "%s: invalid quantization type %d (%s)\n", __func__, qtype, ggml_type_name(qtype)); + return false; + } + + size_t total_size_org = 0; + size_t total_size_new = 0; + + std::vector work; + + std::vector data_u8; + std::vector data_f16; + std::vector data_f32; + + while (true) { + int32_t n_dims; + int32_t length; + int32_t ttype; + + finp.read(reinterpret_cast(&n_dims), sizeof(n_dims)); + finp.read(reinterpret_cast(&length), sizeof(length)); + finp.read(reinterpret_cast(&ttype), sizeof(ttype)); + + if (finp.eof()) { + break; + } + + int32_t nelements = 1; + int32_t ne[4] = { 1, 1, 1, 1 }; + for (int i = 0; i < n_dims; ++i) { + finp.read (reinterpret_cast(&ne[i]), sizeof(ne[i])); + nelements *= ne[i]; + } + + std::string name(length, 0); + finp.read (&name[0], length); + + printf("%64s - [%5d, %5d, %5d], type = %6s ", name.data(), ne[0], ne[1], ne[2], ggml_type_name((ggml_type) ttype)); + + bool quantize = false; + + // check if we should quantize this tensor + for (const auto & s : to_quant) { + if (std::regex_match(name, std::regex(s))) { + quantize = true; + break; + } + } + + // check if we should skip this tensor + for (const auto & s : to_skip) { + if (std::regex_match(name, std::regex(s))) { + quantize = false; + break; + } + } + + // quantize only 2D tensors + quantize &= (n_dims == 2); + + if (quantize) { + if (ttype != GGML_TYPE_F32 && ttype != GGML_TYPE_F16) { + fprintf(stderr, "%s: unsupported ttype %d (%s) for integer quantization\n", __func__, ttype, ggml_type_name((ggml_type) ttype)); + return false; + } + + if (ttype == GGML_TYPE_F16) { + data_f16.resize(nelements); + finp.read(reinterpret_cast(data_f16.data()), nelements * sizeof(ggml_fp16_t)); + data_f32.resize(nelements); + for (int i = 0; i < nelements; ++i) { + data_f32[i] = ggml_fp16_to_fp32(data_f16[i]); + } + } else { + data_f32.resize(nelements); + finp.read(reinterpret_cast(data_f32.data()), nelements * sizeof(float)); + } + + ttype = qtype; + } else { + const int bpe = (ttype == 0) ? sizeof(float) : sizeof(uint16_t); + + data_u8.resize(nelements*bpe); + finp.read(reinterpret_cast(data_u8.data()), nelements * bpe); + } + + fout.write(reinterpret_cast(&n_dims), sizeof(n_dims)); + fout.write(reinterpret_cast(&length), sizeof(length)); + fout.write(reinterpret_cast(&ttype), sizeof(ttype)); + for (int i = 0; i < n_dims; ++i) { + fout.write(reinterpret_cast(&ne[i]), sizeof(ne[i])); + } + fout.write(&name[0], length); + + if (quantize) { + work.resize(nelements); // for quantization + + size_t cur_size = 0; + switch ((ggml_type) ttype) { + case GGML_TYPE_Q4_0: + case GGML_TYPE_Q4_1: + case GGML_TYPE_Q5_0: + case GGML_TYPE_Q5_1: + case GGML_TYPE_Q8_0: + case GGML_TYPE_Q2_K: + case GGML_TYPE_Q3_K: + case GGML_TYPE_Q4_K: + case GGML_TYPE_Q5_K: + case GGML_TYPE_Q6_K: + { + cur_size = ggml_quantize_chunk((ggml_type) ttype, data_f32.data(), work.data(), 0, nelements/ne[0], ne[0], nullptr); + } break; + case GGML_TYPE_F32: + case GGML_TYPE_F16: + case GGML_TYPE_I8: + case GGML_TYPE_I16: + case GGML_TYPE_I32: + case GGML_TYPE_I64: + case GGML_TYPE_F64: + case GGML_TYPE_Q8_1: + case GGML_TYPE_Q8_K: + case GGML_TYPE_IQ2_XXS: + case GGML_TYPE_IQ2_XS: + case GGML_TYPE_IQ2_S: + case GGML_TYPE_IQ3_XXS: + case GGML_TYPE_IQ3_S: + case GGML_TYPE_IQ1_S: + case GGML_TYPE_IQ4_NL: + case GGML_TYPE_IQ4_XS: + case GGML_TYPE_IQ1_M: + case GGML_TYPE_BF16: + case GGML_TYPE_Q4_0_4_4: + case GGML_TYPE_Q4_0_4_8: + case GGML_TYPE_Q4_0_8_8: + case GGML_TYPE_COUNT: + { + fprintf(stderr, "%s: unsupported quantization type %d (%s)\n", __func__, ttype, ggml_type_name((ggml_type) ttype)); + return false; + } + } + + fout.write(reinterpret_cast(work.data()), cur_size); + total_size_new += cur_size; + + printf("size = %8.2f MB -> %8.2f MB\n", nelements * sizeof(float)/1024.0/1024.0, cur_size/1024.0/1024.0); + } else { + printf("size = %8.3f MB\n", data_u8.size()/1024.0/1024.0); + fout.write(reinterpret_cast(data_u8.data()), data_u8.size()); + total_size_new += data_u8.size(); + } + + total_size_org += nelements * sizeof(float); + } + + printf("%s: model size = %8.2f MB\n", __func__, total_size_org/1024.0/1024.0); + printf("%s: quant size = %8.2f MB | ftype = %d (%s)\n", __func__, total_size_new/1024.0/1024.0, ftype, ggml_type_name(qtype)); + + return true; +} diff --git a/examples/common-ggml.h b/examples/common-ggml.h new file mode 100644 index 0000000000000000000000000000000000000000..477de341a1faa99344d05efd968dc58d434b6e24 --- /dev/null +++ b/examples/common-ggml.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ggml.h" + +#include +#include +#include + +enum ggml_ftype ggml_parse_ftype(const char * str); + +void ggml_print_ftypes(FILE * fp = stderr); + +bool ggml_common_quantize_0( + std::ifstream & finp, + std::ofstream & fout, + const ggml_ftype ftype, + const std::vector & to_quant, + const std::vector & to_skip); diff --git a/examples/common-sdl.cpp b/examples/common-sdl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5329ec739b602bb118852e9d1dcba564fd97dc9f --- /dev/null +++ b/examples/common-sdl.cpp @@ -0,0 +1,229 @@ +#include "common-sdl.h" + +audio_async::audio_async(int len_ms) { + m_len_ms = len_ms; + + m_running = false; +} + +audio_async::~audio_async() { + if (m_dev_id_in) { + SDL_CloseAudioDevice(m_dev_id_in); + } +} + +bool audio_async::init(int capture_id, int sample_rate) { + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return false; + } + + SDL_SetHintWithPriority(SDL_HINT_AUDIO_RESAMPLING_MODE, "medium", SDL_HINT_OVERRIDE); + + { + int nDevices = SDL_GetNumAudioDevices(SDL_TRUE); + fprintf(stderr, "%s: found %d capture devices:\n", __func__, nDevices); + for (int i = 0; i < nDevices; i++) { + fprintf(stderr, "%s: - Capture device #%d: '%s'\n", __func__, i, SDL_GetAudioDeviceName(i, SDL_TRUE)); + } + } + + SDL_AudioSpec capture_spec_requested; + SDL_AudioSpec capture_spec_obtained; + + SDL_zero(capture_spec_requested); + SDL_zero(capture_spec_obtained); + + capture_spec_requested.freq = sample_rate; + capture_spec_requested.format = AUDIO_F32; + capture_spec_requested.channels = 1; + capture_spec_requested.samples = 1024; + capture_spec_requested.callback = [](void * userdata, uint8_t * stream, int len) { + audio_async * audio = (audio_async *) userdata; + audio->callback(stream, len); + }; + capture_spec_requested.userdata = this; + + if (capture_id >= 0) { + fprintf(stderr, "%s: attempt to open capture device %d : '%s' ...\n", __func__, capture_id, SDL_GetAudioDeviceName(capture_id, SDL_TRUE)); + m_dev_id_in = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(capture_id, SDL_TRUE), SDL_TRUE, &capture_spec_requested, &capture_spec_obtained, 0); + } else { + fprintf(stderr, "%s: attempt to open default capture device ...\n", __func__); + m_dev_id_in = SDL_OpenAudioDevice(nullptr, SDL_TRUE, &capture_spec_requested, &capture_spec_obtained, 0); + } + + if (!m_dev_id_in) { + fprintf(stderr, "%s: couldn't open an audio device for capture: %s!\n", __func__, SDL_GetError()); + m_dev_id_in = 0; + + return false; + } else { + fprintf(stderr, "%s: obtained spec for input device (SDL Id = %d):\n", __func__, m_dev_id_in); + fprintf(stderr, "%s: - sample rate: %d\n", __func__, capture_spec_obtained.freq); + fprintf(stderr, "%s: - format: %d (required: %d)\n", __func__, capture_spec_obtained.format, + capture_spec_requested.format); + fprintf(stderr, "%s: - channels: %d (required: %d)\n", __func__, capture_spec_obtained.channels, + capture_spec_requested.channels); + fprintf(stderr, "%s: - samples per frame: %d\n", __func__, capture_spec_obtained.samples); + } + + m_sample_rate = capture_spec_obtained.freq; + + m_audio.resize((m_sample_rate*m_len_ms)/1000); + + return true; +} + +bool audio_async::resume() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to resume!\n", __func__); + return false; + } + + if (m_running) { + fprintf(stderr, "%s: already running!\n", __func__); + return false; + } + + SDL_PauseAudioDevice(m_dev_id_in, 0); + + m_running = true; + + return true; +} + +bool audio_async::pause() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to pause!\n", __func__); + return false; + } + + if (!m_running) { + fprintf(stderr, "%s: already paused!\n", __func__); + return false; + } + + SDL_PauseAudioDevice(m_dev_id_in, 1); + + m_running = false; + + return true; +} + +bool audio_async::clear() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to clear!\n", __func__); + return false; + } + + if (!m_running) { + fprintf(stderr, "%s: not running!\n", __func__); + return false; + } + + { + std::lock_guard lock(m_mutex); + + m_audio_pos = 0; + m_audio_len = 0; + } + + return true; +} + +// callback to be called by SDL +void audio_async::callback(uint8_t * stream, int len) { + if (!m_running) { + return; + } + + size_t n_samples = len / sizeof(float); + + if (n_samples > m_audio.size()) { + n_samples = m_audio.size(); + + stream += (len - (n_samples * sizeof(float))); + } + + //fprintf(stderr, "%s: %zu samples, pos %zu, len %zu\n", __func__, n_samples, m_audio_pos, m_audio_len); + + { + std::lock_guard lock(m_mutex); + + if (m_audio_pos + n_samples > m_audio.size()) { + const size_t n0 = m_audio.size() - m_audio_pos; + + memcpy(&m_audio[m_audio_pos], stream, n0 * sizeof(float)); + memcpy(&m_audio[0], stream + n0 * sizeof(float), (n_samples - n0) * sizeof(float)); + + m_audio_pos = (m_audio_pos + n_samples) % m_audio.size(); + m_audio_len = m_audio.size(); + } else { + memcpy(&m_audio[m_audio_pos], stream, n_samples * sizeof(float)); + + m_audio_pos = (m_audio_pos + n_samples) % m_audio.size(); + m_audio_len = std::min(m_audio_len + n_samples, m_audio.size()); + } + } +} + +void audio_async::get(int ms, std::vector & result) { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to get audio from!\n", __func__); + return; + } + + if (!m_running) { + fprintf(stderr, "%s: not running!\n", __func__); + return; + } + + result.clear(); + + { + std::lock_guard lock(m_mutex); + + if (ms <= 0) { + ms = m_len_ms; + } + + size_t n_samples = (m_sample_rate * ms) / 1000; + if (n_samples > m_audio_len) { + n_samples = m_audio_len; + } + + result.resize(n_samples); + + int s0 = m_audio_pos - n_samples; + if (s0 < 0) { + s0 += m_audio.size(); + } + + if (s0 + n_samples > m_audio.size()) { + const size_t n0 = m_audio.size() - s0; + + memcpy(result.data(), &m_audio[s0], n0 * sizeof(float)); + memcpy(&result[n0], &m_audio[0], (n_samples - n0) * sizeof(float)); + } else { + memcpy(result.data(), &m_audio[s0], n_samples * sizeof(float)); + } + } +} + +bool sdl_poll_events() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + { + return false; + } + default: + break; + } + } + + return true; +} diff --git a/examples/common-sdl.h b/examples/common-sdl.h new file mode 100644 index 0000000000000000000000000000000000000000..9ee8a320724ea27a3456743b2cf5d99b20b049bb --- /dev/null +++ b/examples/common-sdl.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +// +// SDL Audio capture +// + +class audio_async { +public: + audio_async(int len_ms); + ~audio_async(); + + bool init(int capture_id, int sample_rate); + + // start capturing audio via the provided SDL callback + // keep last len_ms seconds of audio in a circular buffer + bool resume(); + bool pause(); + bool clear(); + + // callback to be called by SDL + void callback(uint8_t * stream, int len); + + // get audio data from the circular buffer + void get(int ms, std::vector & audio); + +private: + SDL_AudioDeviceID m_dev_id_in = 0; + + int m_len_ms = 0; + int m_sample_rate = 0; + + std::atomic_bool m_running; + std::mutex m_mutex; + + std::vector m_audio; + size_t m_audio_pos = 0; + size_t m_audio_len = 0; +}; + +// Return false if need to quit +bool sdl_poll_events(); diff --git a/examples/common.cpp b/examples/common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11035736b6e4c629b94fc0721b7b891f423646ad --- /dev/null +++ b/examples/common.cpp @@ -0,0 +1,911 @@ +#define _USE_MATH_DEFINES // for M_PI + +#include "common.h" + +// third-party utilities +// use your favorite implementations +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(disable: 4244 4267) // possible loss of data +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef WHISPER_FFMPEG +// as implemented in ffmpeg_trancode.cpp only embedded in common lib if whisper built with ffmpeg support +extern bool ffmpeg_decode_audio(const std::string & ifname, std::vector & wav_data); +#endif + +// Function to check if the next argument exists +static std::string get_next_arg(int& i, int argc, char** argv, const std::string& flag, gpt_params& params) { + if (i + 1 < argc && argv[i + 1][0] != '-') { + return argv[++i]; + } else { + fprintf(stderr, "error: %s requires one argument.\n", flag.c_str()); + gpt_print_usage(argc, argv, params); + exit(0); + } +} + +bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-s" || arg == "--seed") { + params.seed = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-t" || arg == "--threads") { + params.n_threads = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-p" || arg == "--prompt") { + params.prompt = get_next_arg(i, argc, argv, arg, params); + } else if (arg == "-n" || arg == "--n_predict") { + params.n_predict = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-np" || arg == "--n_parallel") { + params.n_parallel = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--top_k") { + params.top_k = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--top_p") { + params.top_p = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--temp") { + params.temp = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--repeat-last-n") { + params.repeat_last_n = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--repeat-penalty") { + params.repeat_penalty = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-b" || arg == "--batch_size") { + params.n_batch= std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-c" || arg == "--context") { + params.n_ctx= std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-ngl" || arg == "--gpu-layers" || arg == "--n-gpu-layers") { + params.n_gpu_layers = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--ignore-eos") { + params.ignore_eos = true; + } else if (arg == "-m" || arg == "--model") { + params.model = get_next_arg(i, argc, argv, arg, params); + } else if (arg == "-i" || arg == "--interactive") { + params.interactive = true; + } else if (arg == "-ip" || arg == "--interactive-port") { + params.interactive = true; + params.interactive_port = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-h" || arg == "--help") { + gpt_print_usage(argc, argv, params); + exit(0); + } else if (arg == "-f" || arg == "--file") { + get_next_arg(i, argc, argv, arg, params); + std::ifstream file(argv[i]); + if (!file) { + fprintf(stderr, "error: failed to open file '%s'\n", argv[i]); + break; + } + std::copy(std::istreambuf_iterator(file), std::istreambuf_iterator(), back_inserter(params.prompt)); + if (params.prompt.back() == '\n') { + params.prompt.pop_back(); + } + } else if (arg == "-tt" || arg == "--token_test") { + params.token_test = get_next_arg(i, argc, argv, arg, params); + } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + gpt_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void gpt_print_usage(int /*argc*/, char ** argv, const gpt_params & params) { + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help show this help message and exit\n"); + fprintf(stderr, " -s SEED, --seed SEED RNG seed (default: -1)\n"); + fprintf(stderr, " -t N, --threads N number of threads to use during computation (default: %d)\n", params.n_threads); + fprintf(stderr, " -p PROMPT, --prompt PROMPT\n"); + fprintf(stderr, " prompt to start generation with (default: random)\n"); + fprintf(stderr, " -f FNAME, --file FNAME\n"); + fprintf(stderr, " load prompt from a file\n"); + fprintf(stderr, " -tt TOKEN_TEST, --token_test TOKEN_TEST\n"); + fprintf(stderr, " test tokenization\n"); + fprintf(stderr, " -n N, --n_predict N number of tokens to predict (default: %d)\n", params.n_predict); + fprintf(stderr, " --top_k N top-k sampling (default: %d)\n", params.top_k); + fprintf(stderr, " --top_p N top-p sampling (default: %.1f)\n", params.top_p); + fprintf(stderr, " --temp N temperature (default: %.1f)\n", params.temp); + fprintf(stderr, " --repeat-last-n N last n tokens to consider for penalize (default: %d, 0 = disabled)\n", params.repeat_last_n); + fprintf(stderr, " --repeat-penalty N penalize repeat sequence of tokens (default: %.2f, 1.0 = disabled)\n", (double)params.repeat_penalty); + fprintf(stderr, " -b N, --batch_size N batch size for prompt processing (default: %d)\n", params.n_batch); + fprintf(stderr, " -c N, --context N context / KV cache size (default: %d)\n", params.n_ctx); + fprintf(stderr, " --ignore-eos ignore EOS token during generation\n"); + fprintf(stderr, " -ngl N, --gpu-layers N number of layers to offload to GPU on supported models (default: %d)\n", params.n_gpu_layers); + fprintf(stderr, " -m FNAME, --model FNAME\n"); + fprintf(stderr, " model path (default: %s)\n", params.model.c_str()); + fprintf(stderr, "\n"); +} + +std::string gpt_random_prompt(std::mt19937 & rng) { + const int r = rng() % 10; + switch (r) { + case 0: return "So"; + case 1: return "Once upon a time"; + case 2: return "When"; + case 3: return "The"; + case 4: return "After"; + case 5: return "If"; + case 6: return "import"; + case 7: return "He"; + case 8: return "She"; + case 9: return "They"; + } + + return "The"; +} + +std::string trim(const std::string & s) { + std::regex e("^\\s+|\\s+$"); + return std::regex_replace(s, e, ""); +} + +std::string replace(const std::string & s, const std::string & from, const std::string & to) { + std::string result = s; + size_t pos = 0; + while ((pos = result.find(from, pos)) != std::string::npos) { + result.replace(pos, from.length(), to); + pos += to.length(); + } + return result; +} + +void gpt_vocab::add_special_token(const std::string & token) { + special_tokens.push_back(token); +} + +std::map json_parse(const std::string & fname) { + std::map result; + + // read file into string + std::string json; + { + std::ifstream ifs(fname); + if (!ifs) { + fprintf(stderr, "Failed to open %s\n", fname.c_str()); + exit(1); + } + + json = std::string((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + } + + if (json[0] != '{') { + return result; + } + + // parse json + { + bool has_key = false; + bool in_token = false; + + std::string str_key = ""; + std::string str_val = ""; + + int n = json.size(); + for (int i = 1; i < n; ++i) { + if (!in_token) { + if (json[i] == ' ') continue; + if (json[i] == '"') { + in_token = true; + continue; + } + } else { + if (json[i] == '\\' && i+1 < n) { + if (has_key == false) { + str_key += json[i]; + } else { + str_val += json[i]; + } + ++i; + } else if (json[i] == '"') { + if (has_key == false) { + has_key = true; + ++i; + while (json[i] == ' ') ++i; + ++i; // : + while (json[i] == ' ') ++i; + if (json[i] != '\"') { + while (json[i] != ',' && json[i] != '}') { + str_val += json[i++]; + } + has_key = false; + } else { + in_token = true; + continue; + } + } else { + has_key = false; + } + + str_key = ::replace(str_key, "\\u0120", " " ); // \u0120 -> space + str_key = ::replace(str_key, "\\u010a", "\n"); // \u010a -> new line + str_key = ::replace(str_key, "\\\"", "\""); // \\\" -> " + + try { + result[str_key] = std::stoi(str_val); + } catch (...) { + //fprintf(stderr, "%s: ignoring key '%s' with value '%s'\n", fname.c_str(), str_key.c_str(), str_val.c_str()); + + } + str_key = ""; + str_val = ""; + in_token = false; + continue; + } + if (has_key == false) { + str_key += json[i]; + } else { + str_val += json[i]; + } + } + } + } + + return result; +} + +std::string convert_to_utf8(const std::wstring & input) { + std::wstring_convert> converter; + return converter.to_bytes(input); +} + + +std::wstring convert_to_wstring(const std::string & input) { + std::wstring_convert> converter; + return converter.from_bytes(input); +} + +void gpt_split_words(std::string str, std::vector& words) { + const std::string pattern = R"('s|'t|'re|'ve|'m|'ll|'d| ?[[:alpha:]]+| ?[[:digit:]]+| ?[^\s[:alpha:][:digit:]]+|\s+(?!\S)|\s+)"; + const std::regex re(pattern); + std::smatch m; + + while (std::regex_search(str, m, re)) { + for (auto x : m) { + words.push_back(x); + } + str = m.suffix(); + } +} + +std::vector gpt_tokenize(const gpt_vocab & vocab, const std::string & text) { + std::vector words; + + // first split the text into words + { + std::string str = text; + + // Generate the subpattern from the special_tokens vector if it's not empty + if (!vocab.special_tokens.empty()) { + const std::regex escape(R"([\[\\\^\$\.\|\?\*\+\(\)\{\}])"); + std::string special_tokens_subpattern; + for (const auto & token : vocab.special_tokens) { + if (!special_tokens_subpattern.empty()) { + special_tokens_subpattern += "|"; + } + special_tokens_subpattern += std::regex_replace(token, escape, R"(\$&)"); + } + + std::regex re(special_tokens_subpattern); + std::smatch m; + // Split the text by special tokens. + while (std::regex_search(str, m, re)) { + // Split the substrings in-between special tokens into words. + gpt_split_words(m.prefix(), words); + // Add matched special tokens as words. + for (auto x : m) { + words.push_back(x); + } + str = m.suffix(); + } + // Remaining text without special tokens will be handled below. + } + + gpt_split_words(str, words); + } + + // find the longest token that forms each word in words: + std::vector tokens; + for (const auto & word : words) { + for (int i = 0; i < (int) word.size(); ){ + for (int j = word.size() - 1; j >= i; j--){ + auto cand = word.substr(i, j-i+1); + auto it = vocab.token_to_id.find(cand); + if (it != vocab.token_to_id.end()){ // word.substr(i, j-i+1) in vocab + tokens.push_back(it->second); + i = j + 1; + break; + } + else if (j == i){ // word.substr(i, 1) has no matching + fprintf(stderr, "%s: unknown token '%s'\n", __func__, word.substr(i, 1).data()); + i++; + } + } + } + } + + return tokens; +} + +static std::vector parse_tokens_from_string(const std::string& input, char delimiter) { + std::vector output; + std::stringstream ss(input); + std::string token; + + while (std::getline(ss, token, delimiter)) { + output.push_back(std::stoi(token)); + } + + return output; +} + +static std::map> extract_tests_from_file(const std::string & fpath_test){ + if (fpath_test.empty()){ + fprintf(stderr, "%s : No test file found.\n", __func__); + return std::map>(); + } + + std::map> tests; + + auto fin = std::ifstream(fpath_test, std::ios_base::in); + const char * delimeter = " => "; + const char del_tok = ','; + std::string line; + while (std::getline(fin, line)) { + size_t delimiterPos = line.find(delimeter); + if (delimiterPos != std::string::npos) { + std::string text = line.substr(0, delimiterPos); + std::string s_tokens = line.substr(delimiterPos + std::strlen(delimeter)); + tests[text] = parse_tokens_from_string(s_tokens, del_tok); + } + } + return tests; +} + +void test_gpt_tokenizer(gpt_vocab & vocab, const std::string & fpath_test){ + std::map> tests = extract_tests_from_file(fpath_test); + + size_t n_fails = 0; + + for (const auto & test : tests) { + std::vector tokens = gpt_tokenize(vocab, test.first); + + if (tokens != test.second){ + n_fails++; + + // print out failure cases + fprintf(stderr, "%s : failed test: '%s'\n", __func__, test.first.c_str()); + fprintf(stderr, "%s : tokens in hf: ", __func__); + for (const auto & t : test.second) { + fprintf(stderr, "%s(%d), ", vocab.id_to_token[t].c_str(), t); + } + fprintf(stderr, "\n"); + fprintf(stderr, "%s : tokens in ggml: ", __func__); + for (const auto & t : tokens) { + fprintf(stderr, "%s(%d), ", vocab.id_to_token[t].c_str(), t); + } + fprintf(stderr, "\n"); + } + } + + fprintf(stderr, "%s : %zu tests failed out of %zu tests.\n", __func__, n_fails, tests.size()); +} + +bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab) { + printf("%s: loading vocab from '%s'\n", __func__, fname.c_str()); + + vocab.token_to_id = ::json_parse(fname); + + for (const auto & kv : vocab.token_to_id) { + vocab.id_to_token[kv.second] = kv.first; + } + + printf("%s: vocab size = %d\n", __func__, (int) vocab.token_to_id.size()); + + // print the vocabulary + //for (auto kv : vocab.token_to_id) { + // printf("'%s' -> %d\n", kv.first.data(), kv.second); + //} + + return true; +} + +gpt_vocab::id gpt_sample_top_k_top_p( + const gpt_vocab & vocab, + const float * logits, + int top_k, + double top_p, + double temp, + std::mt19937 & rng) { + int n_logits = vocab.id_to_token.size(); + + std::vector> logits_id; + logits_id.reserve(n_logits); + + { + const double scale = 1.0/temp; + for (int i = 0; i < n_logits; ++i) { + logits_id.push_back(std::make_pair(logits[i]*scale, i)); + } + } + + // find the top K tokens + std::partial_sort( + logits_id.begin(), + logits_id.begin() + top_k, logits_id.end(), + [](const std::pair & a, const std::pair & b) { + return a.first > b.first; + }); + + logits_id.resize(top_k); + + double maxl = -INFINITY; + for (const auto & kv : logits_id) { + maxl = std::max(maxl, kv.first); + } + + // compute probs for the top K tokens + std::vector probs; + probs.reserve(logits_id.size()); + + double sum = 0.0; + for (const auto & kv : logits_id) { + double p = exp(kv.first - maxl); + probs.push_back(p); + sum += p; + } + + // normalize the probs + for (auto & p : probs) { + p /= sum; + } + + if (top_p < 1.0f) { + double cumsum = 0.0f; + for (int i = 0; i < top_k; i++) { + cumsum += probs[i]; + if (cumsum >= top_p) { + top_k = i + 1; + probs.resize(top_k); + logits_id.resize(top_k); + break; + } + } + + cumsum = 1.0/cumsum; + for (int i = 0; i < (int) probs.size(); i++) { + probs[i] *= cumsum; + } + } + + //printf("\n"); + //for (int i = 0; i < (int) probs.size(); i++) { + // printf("%d: '%s' %f\n", i, vocab.id_to_token.at(logits_id[i].second).c_str(), probs[i]); + //} + //exit(0); + + std::discrete_distribution<> dist(probs.begin(), probs.end()); + int idx = dist(rng); + + return logits_id[idx].second; +} + +gpt_vocab::id gpt_sample_top_k_top_p_repeat( + const gpt_vocab & vocab, + const float * logits, + const int32_t * last_n_tokens_data, + size_t last_n_tokens_data_size, + int top_k, + double top_p, + double temp, + int repeat_last_n, + float repeat_penalty, + std::mt19937 & rng) { + + int n_logits = vocab.id_to_token.size(); + + const auto * plogits = logits; + + const auto last_n_tokens = std::vector(last_n_tokens_data, last_n_tokens_data + last_n_tokens_data_size); + + if (temp <= 0) { + // select the token with the highest logit directly + float max_logit = plogits[0]; + gpt_vocab::id max_id = 0; + + for (int i = 1; i < n_logits; ++i) { + if (plogits[i] > max_logit) { + max_logit = plogits[i]; + max_id = i; + } + } + return max_id; + } + + + std::vector> logits_id; + logits_id.reserve(n_logits); + + { + const float scale = 1.0f/temp; + for (int i = 0; i < n_logits; ++i) { + // repetition penalty from ctrl paper (https://arxiv.org/abs/1909.05858) + // credit https://github.com/facebookresearch/llama/compare/main...shawwn:llama:main + if (repeat_last_n > 0 && std::find(last_n_tokens.end()-repeat_last_n, last_n_tokens.end(), i) != last_n_tokens.end()) { + // if score < 0 then repetition penalty has to multiplied to reduce the previous token probability + if (plogits[i] < 0.0f) { + logits_id.push_back(std::make_pair(plogits[i]*scale*repeat_penalty, i)); + } else { + logits_id.push_back(std::make_pair(plogits[i]*scale/repeat_penalty, i)); + } + } else { + logits_id.push_back(std::make_pair(plogits[i]*scale, i)); + } + } + } + + // find the top K tokens + std::partial_sort( + logits_id.begin(), + logits_id.begin() + top_k, logits_id.end(), + [](const std::pair & a, const std::pair & b) { + return a.first > b.first; + }); + + logits_id.resize(top_k); + + double maxl = -INFINITY; + for (const auto & kv : logits_id) { + maxl = std::max(maxl, kv.first); + } + + // compute probs for the top K tokens + std::vector probs; + probs.reserve(logits_id.size()); + + double sum = 0.0; + for (const auto & kv : logits_id) { + double p = exp(kv.first - maxl); + probs.push_back(p); + sum += p; + } + + // normalize the probs + for (auto & p : probs) { + p /= sum; + } + + if (top_p < 1.0f) { + double cumsum = 0.0f; + for (int i = 0; i < top_k; i++) { + cumsum += probs[i]; + if (cumsum >= top_p) { + top_k = i + 1; + probs.resize(top_k); + logits_id.resize(top_k); + break; + } + } + + cumsum = 1.0/cumsum; + for (int i = 0; i < (int) probs.size(); i++) { + probs[i] *= cumsum; + } + } + +// printf("\n"); +// for (int i = 0; i < (int) probs.size(); i++) { +// for (int i = 0; i < 10; i++) { +// printf("%d: '%s' %f\n", i, vocab.id_to_token.at(logits_id[i].second).c_str(), probs[i]); +// } + + std::discrete_distribution<> dist(probs.begin(), probs.end()); + int idx = dist(rng); + + return logits_id[idx].second; + +} + +bool is_wav_buffer(const std::string buf) { + // RIFF ref: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format + // WAV ref: https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html + if (buf.size() < 12 || buf.substr(0, 4) != "RIFF" || buf.substr(8, 4) != "WAVE") { + return false; + } + + uint32_t chunk_size = *reinterpret_cast(buf.data() + 4); + if (chunk_size + 8 != buf.size()) { + return false; + } + + return true; +} + +bool read_wav(const std::string & fname, std::vector& pcmf32, std::vector>& pcmf32s, bool stereo) { + drwav wav; + std::vector wav_data; // used for pipe input from stdin or ffmpeg decoding output + + if (fname == "-") { + { + #ifdef _WIN32 + _setmode(_fileno(stdin), _O_BINARY); + #endif + + uint8_t buf[1024]; + while (true) + { + const size_t n = fread(buf, 1, sizeof(buf), stdin); + if (n == 0) { + break; + } + wav_data.insert(wav_data.end(), buf, buf + n); + } + } + + if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) { + fprintf(stderr, "error: failed to open WAV file from stdin\n"); + return false; + } + + fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, wav_data.size()); + } + else if (is_wav_buffer(fname)) { + if (drwav_init_memory(&wav, fname.c_str(), fname.size(), nullptr) == false) { + fprintf(stderr, "error: failed to open WAV file from fname buffer\n"); + return false; + } + } + else if (drwav_init_file(&wav, fname.c_str(), nullptr) == false) { +#if defined(WHISPER_FFMPEG) + if (ffmpeg_decode_audio(fname, wav_data) != 0) { + fprintf(stderr, "error: failed to ffmpeg decode '%s' \n", fname.c_str()); + return false; + } + if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) { + fprintf(stderr, "error: failed to read wav data as wav \n"); + return false; + } +#else + fprintf(stderr, "error: failed to open '%s' as WAV file\n", fname.c_str()); + return false; +#endif + } + + if (wav.channels != 1 && wav.channels != 2) { + fprintf(stderr, "%s: WAV file '%s' must be mono or stereo\n", __func__, fname.c_str()); + drwav_uninit(&wav); + return false; + } + + if (stereo && wav.channels != 2) { + fprintf(stderr, "%s: WAV file '%s' must be stereo for diarization\n", __func__, fname.c_str()); + drwav_uninit(&wav); + return false; + } + + if (wav.sampleRate != COMMON_SAMPLE_RATE) { + fprintf(stderr, "%s: WAV file '%s' must be %i kHz\n", __func__, fname.c_str(), COMMON_SAMPLE_RATE/1000); + drwav_uninit(&wav); + return false; + } + + if (wav.bitsPerSample != 16) { + fprintf(stderr, "%s: WAV file '%s' must be 16-bit\n", __func__, fname.c_str()); + drwav_uninit(&wav); + return false; + } + + const uint64_t n = wav_data.empty() ? wav.totalPCMFrameCount : wav_data.size()/(wav.channels*wav.bitsPerSample/8); + + std::vector pcm16; + pcm16.resize(n*wav.channels); + drwav_read_pcm_frames_s16(&wav, n, pcm16.data()); + drwav_uninit(&wav); + + // convert to mono, float + pcmf32.resize(n); + if (wav.channels == 1) { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[i])/32768.0f; + } + } else { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[2*i] + pcm16[2*i + 1])/65536.0f; + } + } + + if (stereo) { + // convert to stereo, float + pcmf32s.resize(2); + + pcmf32s[0].resize(n); + pcmf32s[1].resize(n); + for (uint64_t i = 0; i < n; i++) { + pcmf32s[0][i] = float(pcm16[2*i])/32768.0f; + pcmf32s[1][i] = float(pcm16[2*i + 1])/32768.0f; + } + } + + return true; +} + +void high_pass_filter(std::vector & data, float cutoff, float sample_rate) { + const float rc = 1.0f / (2.0f * M_PI * cutoff); + const float dt = 1.0f / sample_rate; + const float alpha = dt / (rc + dt); + + float y = data[0]; + + for (size_t i = 1; i < data.size(); i++) { + y = alpha * (y + data[i] - data[i - 1]); + data[i] = y; + } +} + +bool vad_simple(std::vector & pcmf32, int sample_rate, int last_ms, float vad_thold, float freq_thold, bool verbose) { + const int n_samples = pcmf32.size(); + const int n_samples_last = (sample_rate * last_ms) / 1000; + + if (n_samples_last >= n_samples) { + // not enough samples - assume no speech + return false; + } + + if (freq_thold > 0.0f) { + high_pass_filter(pcmf32, freq_thold, sample_rate); + } + + float energy_all = 0.0f; + float energy_last = 0.0f; + + for (int i = 0; i < n_samples; i++) { + energy_all += fabsf(pcmf32[i]); + + if (i >= n_samples - n_samples_last) { + energy_last += fabsf(pcmf32[i]); + } + } + + energy_all /= n_samples; + energy_last /= n_samples_last; + + if (verbose) { + fprintf(stderr, "%s: energy_all: %f, energy_last: %f, vad_thold: %f, freq_thold: %f\n", __func__, energy_all, energy_last, vad_thold, freq_thold); + } + + if (energy_last > vad_thold*energy_all) { + return false; + } + + return true; +} + +float similarity(const std::string & s0, const std::string & s1) { + const size_t len0 = s0.size() + 1; + const size_t len1 = s1.size() + 1; + + std::vector col(len1, 0); + std::vector prevCol(len1, 0); + + for (size_t i = 0; i < len1; i++) { + prevCol[i] = i; + } + + for (size_t i = 0; i < len0; i++) { + col[0] = i; + for (size_t j = 1; j < len1; j++) { + col[j] = std::min(std::min(1 + col[j - 1], 1 + prevCol[j]), prevCol[j - 1] + (i > 0 && s0[i - 1] == s1[j - 1] ? 0 : 1)); + } + col.swap(prevCol); + } + + const float dist = prevCol[len1 - 1]; + + return 1.0f - (dist / std::max(s0.size(), s1.size())); +} + +bool sam_params_parse(int argc, char ** argv, sam_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-s" || arg == "--seed") { + params.seed = std::stoi(argv[++i]); + } else if (arg == "-t" || arg == "--threads") { + params.n_threads = std::stoi(argv[++i]); + } else if (arg == "-m" || arg == "--model") { + params.model = argv[++i]; + } else if (arg == "-i" || arg == "--inp") { + params.fname_inp = argv[++i]; + } else if (arg == "-o" || arg == "--out") { + params.fname_out = argv[++i]; + } else if (arg == "-h" || arg == "--help") { + sam_print_usage(argc, argv, params); + exit(0); + } else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + sam_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void sam_print_usage(int /*argc*/, char ** argv, const sam_params & params) { + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help show this help message and exit\n"); + fprintf(stderr, " -s SEED, --seed SEED RNG seed (default: -1)\n"); + fprintf(stderr, " -t N, --threads N number of threads to use during computation (default: %d)\n", params.n_threads); + fprintf(stderr, " -m FNAME, --model FNAME\n"); + fprintf(stderr, " model path (default: %s)\n", params.model.c_str()); + fprintf(stderr, " -i FNAME, --inp FNAME\n"); + fprintf(stderr, " input file (default: %s)\n", params.fname_inp.c_str()); + fprintf(stderr, " -o FNAME, --out FNAME\n"); + fprintf(stderr, " output file (default: %s)\n", params.fname_out.c_str()); + fprintf(stderr, "\n"); +} + +// 500 -> 00:05.000 +// 6000 -> 01:00.000 +std::string to_timestamp(int64_t t, bool comma) { + int64_t msec = t * 10; + int64_t hr = msec / (1000 * 60 * 60); + msec = msec - hr * (1000 * 60 * 60); + int64_t min = msec / (1000 * 60); + msec = msec - min * (1000 * 60); + int64_t sec = msec / 1000; + msec = msec - sec * 1000; + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d%s%03d", (int) hr, (int) min, (int) sec, comma ? "," : ".", (int) msec); + + return std::string(buf); +} + +int timestamp_to_sample(int64_t t, int n_samples, int whisper_sample_rate) { + return std::max(0, std::min((int) n_samples - 1, (int) ((t*whisper_sample_rate)/100))); +} + +bool is_file_exist(const char *fileName) +{ + std::ifstream infile(fileName); + return infile.good(); +} + +bool speak_with_file(const std::string & command, const std::string & text, const std::string & path, int voice_id) +{ + std::ofstream speak_file(path.c_str()); + if (speak_file.fail()) { + fprintf(stderr, "%s: failed to open speak_file\n", __func__); + return false; + } else { + speak_file.write(text.c_str(), text.size()); + speak_file.close(); + int ret = system((command + " " + std::to_string(voice_id) + " " + path).c_str()); + if (ret != 0) { + fprintf(stderr, "%s: failed to speak\n", __func__); + return false; + } + } + return true; +} diff --git a/examples/common.h b/examples/common.h new file mode 100644 index 0000000000000000000000000000000000000000..8c514c9f59032e5c07d3426fb4d0546e5f89beea --- /dev/null +++ b/examples/common.h @@ -0,0 +1,343 @@ +// Various helper functions and utilities + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#define COMMON_SAMPLE_RATE 16000 + +// +// GPT CLI argument parsing +// + +struct gpt_params { + int32_t seed = -1; // RNG seed + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t n_predict = 200; // new tokens to predict + int32_t n_parallel = 1; // number of parallel streams + int32_t n_batch = 32; // batch size for prompt processing + int32_t n_ctx = 2048; // context size (this is the KV cache max size) + int32_t n_gpu_layers = 0; // number of layers to offlload to the GPU + + bool ignore_eos = false; // ignore EOS token when generating text + + // sampling parameters + int32_t top_k = 40; + float top_p = 0.9f; + float temp = 0.9f; + int32_t repeat_last_n = 64; + float repeat_penalty = 1.00f; + + std::string model = "models/gpt-2-117M/ggml-model.bin"; // model path + std::string prompt = ""; + std::string token_test = ""; + + bool interactive = false; + int32_t interactive_port = -1; +}; + +bool gpt_params_parse(int argc, char ** argv, gpt_params & params); + +void gpt_print_usage(int argc, char ** argv, const gpt_params & params); + +std::string gpt_random_prompt(std::mt19937 & rng); + +// +// Vocab utils +// + +std::string trim(const std::string & s); + +std::string replace( + const std::string & s, + const std::string & from, + const std::string & to); + +struct gpt_vocab { + using id = int32_t; + using token = std::string; + + std::map token_to_id; + std::map id_to_token; + std::vector special_tokens; + + void add_special_token(const std::string & token); +}; + +// poor-man's JSON parsing +std::map json_parse(const std::string & fname); + +std::string convert_to_utf8(const std::wstring & input); + +std::wstring convert_to_wstring(const std::string & input); + +void gpt_split_words(std::string str, std::vector& words); + +// split text into tokens +// +// ref: https://github.com/openai/gpt-2/blob/a74da5d99abaaba920de8131d64da2862a8f213b/src/encoder.py#L53 +// +// Regex (Python): +// r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""" +// +// Regex (C++): +// R"('s|'t|'re|'ve|'m|'ll|'d| ?[[:alpha:]]+| ?[[:digit:]]+| ?[^\s[:alpha:][:digit:]]+|\s+(?!\S)|\s+)" +// +std::vector gpt_tokenize(const gpt_vocab & vocab, const std::string & text); + +// test outputs of gpt_tokenize +// +// - compare with tokens generated by the huggingface tokenizer +// - test cases are chosen based on the model's main language (under 'prompt' directory) +// - if all sentences are tokenized identically, print 'All tests passed.' +// - otherwise, print sentence, huggingface tokens, ggml tokens +// +void test_gpt_tokenizer(gpt_vocab & vocab, const std::string & fpath_test); + +// load the tokens from encoder.json +bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab); + +// sample next token given probabilities for each embedding +// +// - consider only the top K tokens +// - from them, consider only the top tokens with cumulative probability > P +// +// TODO: not sure if this implementation is correct +// TODO: temperature is not implemented +// +gpt_vocab::id gpt_sample_top_k_top_p( + const gpt_vocab & vocab, + const float * logits, + int top_k, + double top_p, + double temp, + std::mt19937 & rng); + +gpt_vocab::id gpt_sample_top_k_top_p_repeat( + const gpt_vocab & vocab, + const float * logits, + const int32_t * last_n_tokens_data, + size_t last_n_tokens_data_size, + int top_k, + double top_p, + double temp, + int repeat_last_n, + float repeat_penalty, + std::mt19937 & rng); + +// +// Audio utils +// + +// Check if a buffer is a WAV audio file +bool is_wav_buffer(const std::string buf); + +// Read WAV audio file and store the PCM data into pcmf32 +// fname can be a buffer of WAV data instead of a filename +// The sample rate of the audio must be equal to COMMON_SAMPLE_RATE +// If stereo flag is set and the audio has 2 channels, the pcmf32s will contain 2 channel PCM +bool read_wav( + const std::string & fname, + std::vector & pcmf32, + std::vector> & pcmf32s, + bool stereo); + +// Write PCM data into WAV audio file +class wav_writer { +private: + std::ofstream file; + uint32_t dataSize = 0; + std::string wav_filename; + + bool write_header(const uint32_t sample_rate, + const uint16_t bits_per_sample, + const uint16_t channels) { + + file.write("RIFF", 4); + file.write("\0\0\0\0", 4); // Placeholder for file size + file.write("WAVE", 4); + file.write("fmt ", 4); + + const uint32_t sub_chunk_size = 16; + const uint16_t audio_format = 1; // PCM format + const uint32_t byte_rate = sample_rate * channels * bits_per_sample / 8; + const uint16_t block_align = channels * bits_per_sample / 8; + + file.write(reinterpret_cast(&sub_chunk_size), 4); + file.write(reinterpret_cast(&audio_format), 2); + file.write(reinterpret_cast(&channels), 2); + file.write(reinterpret_cast(&sample_rate), 4); + file.write(reinterpret_cast(&byte_rate), 4); + file.write(reinterpret_cast(&block_align), 2); + file.write(reinterpret_cast(&bits_per_sample), 2); + file.write("data", 4); + file.write("\0\0\0\0", 4); // Placeholder for data size + + return true; + } + + // It is assumed that PCM data is normalized to a range from -1 to 1 + bool write_audio(const float * data, size_t length) { + for (size_t i = 0; i < length; ++i) { + const int16_t intSample = int16_t(data[i] * 32767); + file.write(reinterpret_cast(&intSample), sizeof(int16_t)); + dataSize += sizeof(int16_t); + } + if (file.is_open()) { + file.seekp(4, std::ios::beg); + uint32_t fileSize = 36 + dataSize; + file.write(reinterpret_cast(&fileSize), 4); + file.seekp(40, std::ios::beg); + file.write(reinterpret_cast(&dataSize), 4); + file.seekp(0, std::ios::end); + } + return true; + } + + bool open_wav(const std::string & filename) { + if (filename != wav_filename) { + if (file.is_open()) { + file.close(); + } + } + if (!file.is_open()) { + file.open(filename, std::ios::binary); + wav_filename = filename; + dataSize = 0; + } + return file.is_open(); + } + +public: + bool open(const std::string & filename, + const uint32_t sample_rate, + const uint16_t bits_per_sample, + const uint16_t channels) { + + if (open_wav(filename)) { + write_header(sample_rate, bits_per_sample, channels); + } else { + return false; + } + + return true; + } + + bool close() { + file.close(); + return true; + } + + bool write(const float * data, size_t length) { + return write_audio(data, length); + } + + ~wav_writer() { + if (file.is_open()) { + file.close(); + } + } +}; + + +// Apply a high-pass frequency filter to PCM audio +// Suppresses frequencies below cutoff Hz +void high_pass_filter( + std::vector & data, + float cutoff, + float sample_rate); + +// Basic voice activity detection (VAD) using audio energy adaptive threshold +bool vad_simple( + std::vector & pcmf32, + int sample_rate, + int last_ms, + float vad_thold, + float freq_thold, + bool verbose); + +// compute similarity between two strings using Levenshtein distance +float similarity(const std::string & s0, const std::string & s1); + +// +// SAM argument parsing +// + +struct sam_params { + int32_t seed = -1; // RNG seed + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + + std::string model = "models/sam-vit-b/ggml-model-f16.bin"; // model path + std::string fname_inp = "img.jpg"; + std::string fname_out = "img.out"; +}; + +bool sam_params_parse(int argc, char ** argv, sam_params & params); + +void sam_print_usage(int argc, char ** argv, const sam_params & params); + +// +// Terminal utils +// + +#define SQR(X) ((X) * (X)) +#define UNCUBE(x) x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40 + +/** + * Quantizes 24-bit RGB to xterm256 code range [16,256). + */ +static int rgb2xterm256(int r, int g, int b) { + unsigned char cube[] = {0, 0137, 0207, 0257, 0327, 0377}; + int av, ir, ig, ib, il, qr, qg, qb, ql; + av = r * .299 + g * .587 + b * .114 + .5; + ql = (il = av > 238 ? 23 : (av - 3) / 10) * 10 + 8; + qr = cube[(ir = UNCUBE(r))]; + qg = cube[(ig = UNCUBE(g))]; + qb = cube[(ib = UNCUBE(b))]; + if (SQR(qr - r) + SQR(qg - g) + SQR(qb - b) <= + SQR(ql - r) + SQR(ql - g) + SQR(ql - b)) + return ir * 36 + ig * 6 + ib + 020; + return il + 0350; +} + +static std::string set_xterm256_foreground(int r, int g, int b) { + int x = rgb2xterm256(r, g, b); + std::ostringstream oss; + oss << "\033[38;5;" << x << "m"; + return oss.str(); +} + +// Lowest is red, middle is yellow, highest is green. Color scheme from +// Paul Tol; it is colorblind friendly https://personal.sron.nl/~pault/ +const std::vector k_colors = { + set_xterm256_foreground(220, 5, 12), + set_xterm256_foreground(232, 96, 28), + set_xterm256_foreground(241, 147, 45), + set_xterm256_foreground(246, 193, 65), + set_xterm256_foreground(247, 240, 86), + set_xterm256_foreground(144, 201, 135), + set_xterm256_foreground( 78, 178, 101), +}; + +// +// Other utils +// + +// convert timestamp to string, 6000 -> 01:00.000 +std::string to_timestamp(int64_t t, bool comma = false); + +// given a timestamp get the sample +int timestamp_to_sample(int64_t t, int n_samples, int whisper_sample_rate); + +// check if file exists using ifstream +bool is_file_exist(const char *fileName); + +// write text to file, and call system("command voice_id file") +bool speak_with_file(const std::string & command, const std::string & text, const std::string & path, int voice_id); diff --git a/examples/dr_wav.h b/examples/dr_wav.h new file mode 100644 index 0000000000000000000000000000000000000000..fd3e95b34a0fadcffcc94e01a353339975f18fb7 --- /dev/null +++ b/examples/dr_wav.h @@ -0,0 +1,6434 @@ +/* +WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_wav - v0.12.16 - 2020-12-02 + +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +RELEASE NOTES - VERSION 0.12 +============================ +Version 0.12 includes breaking changes to custom chunk handling. + + +Changes to Chunk Callback +------------------------- +dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been updated to include both the +container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file. + +Previously, there was no direct way to determine the container, and therefore no way to discriminate against the different IDs in the chunk header (RIFF and +Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use. + +Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk +callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the +`DR_WAVE_FORMAT_*` tokens. +*/ + +/* +Introduction +============ +This is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_WAV_IMPLEMENTATION + #include "dr_wav.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data: + + ```c + drwav wav; + if (!drwav_init_file(&wav, "my_song.wav", NULL)) { + // Error opening WAV file. + } + + drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); + size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + + ... + + drwav_uninit(&wav); + ``` + +If you just want to quickly open and read the audio data in a single operation you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drwav_uint64 totalPCMFrameCount; + float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Error opening and reading WAV file. + } + + ... + + drwav_free(pSampleData); + ``` + +The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the +audio data in its internal format (see notes below for supported formats): + + ```c + size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + ``` + +You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format: + + ```c + size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); + ``` + +dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`, +`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk. + + ```c + drwav_data_format format; + format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. + format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. + format.channels = 2; + format.sampleRate = 44100; + format.bitsPerSample = 16; + drwav_init_file_write(&wav, "data/recording.wav", &format, NULL); + + ... + + drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); + ``` + +dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention. + + +Build Options +============= +#define these options before including this file. + +#define DR_WAV_NO_CONVERSION_API + Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`. + +#define DR_WAV_NO_STDIO + Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc. + + + +Notes +===== +- Samples are always interleaved. +- The default read function does not do any data conversion. Use `drwav_read_pcm_frames_f32()`, `drwav_read_pcm_frames_s32()` and `drwav_read_pcm_frames_s16()` + to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. Tested and supported internal + formats include the following: + - Unsigned 8-bit PCM + - Signed 12-bit PCM + - Signed 16-bit PCM + - Signed 24-bit PCM + - Signed 32-bit PCM + - IEEE 32-bit floating point + - IEEE 64-bit floating point + - A-law and u-law + - Microsoft ADPCM + - IMA ADPCM (DVI, format code 0x11) +- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. +*/ + +#ifndef dr_wav_h +#define dr_wav_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRWAV_STRINGIFY(x) #x +#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) + +#define DRWAV_VERSION_MAJOR 0 +#define DRWAV_VERSION_MINOR 12 +#define DRWAV_VERSION_REVISION 16 +#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) + +#include /* For size_t. */ + +/* Sized types. */ +typedef signed char drwav_int8; +typedef unsigned char drwav_uint8; +typedef signed short drwav_int16; +typedef unsigned short drwav_uint16; +typedef signed int drwav_int32; +typedef unsigned int drwav_uint32; +#if defined(_MSC_VER) + typedef signed __int64 drwav_int64; + typedef unsigned __int64 drwav_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drwav_int64; + typedef unsigned long long drwav_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + typedef drwav_uint64 drwav_uintptr; +#else + typedef drwav_uint32 drwav_uintptr; +#endif +typedef drwav_uint8 drwav_bool8; +typedef drwav_uint32 drwav_bool32; +#define DRWAV_TRUE 1 +#define DRWAV_FALSE 0 + +#if !defined(DRWAV_API) + #if defined(DRWAV_DLL) + #if defined(_WIN32) + #define DRWAV_DLL_IMPORT __declspec(dllimport) + #define DRWAV_DLL_EXPORT __declspec(dllexport) + #define DRWAV_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRWAV_DLL_IMPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_EXPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRWAV_DLL_IMPORT + #define DRWAV_DLL_EXPORT + #define DRWAV_DLL_PRIVATE static + #endif + #endif + + #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) + #define DRWAV_API DRWAV_DLL_EXPORT + #else + #define DRWAV_API DRWAV_DLL_IMPORT + #endif + #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE + #else + #define DRWAV_API extern + #define DRWAV_PRIVATE static + #endif +#endif + +typedef drwav_int32 drwav_result; +#define DRWAV_SUCCESS 0 +#define DRWAV_ERROR -1 /* A generic error. */ +#define DRWAV_INVALID_ARGS -2 +#define DRWAV_INVALID_OPERATION -3 +#define DRWAV_OUT_OF_MEMORY -4 +#define DRWAV_OUT_OF_RANGE -5 +#define DRWAV_ACCESS_DENIED -6 +#define DRWAV_DOES_NOT_EXIST -7 +#define DRWAV_ALREADY_EXISTS -8 +#define DRWAV_TOO_MANY_OPEN_FILES -9 +#define DRWAV_INVALID_FILE -10 +#define DRWAV_TOO_BIG -11 +#define DRWAV_PATH_TOO_LONG -12 +#define DRWAV_NAME_TOO_LONG -13 +#define DRWAV_NOT_DIRECTORY -14 +#define DRWAV_IS_DIRECTORY -15 +#define DRWAV_DIRECTORY_NOT_EMPTY -16 +#define DRWAV_END_OF_FILE -17 +#define DRWAV_NO_SPACE -18 +#define DRWAV_BUSY -19 +#define DRWAV_IO_ERROR -20 +#define DRWAV_INTERRUPT -21 +#define DRWAV_UNAVAILABLE -22 +#define DRWAV_ALREADY_IN_USE -23 +#define DRWAV_BAD_ADDRESS -24 +#define DRWAV_BAD_SEEK -25 +#define DRWAV_BAD_PIPE -26 +#define DRWAV_DEADLOCK -27 +#define DRWAV_TOO_MANY_LINKS -28 +#define DRWAV_NOT_IMPLEMENTED -29 +#define DRWAV_NO_MESSAGE -30 +#define DRWAV_BAD_MESSAGE -31 +#define DRWAV_NO_DATA_AVAILABLE -32 +#define DRWAV_INVALID_DATA -33 +#define DRWAV_TIMEOUT -34 +#define DRWAV_NO_NETWORK -35 +#define DRWAV_NOT_UNIQUE -36 +#define DRWAV_NOT_SOCKET -37 +#define DRWAV_NO_ADDRESS -38 +#define DRWAV_BAD_PROTOCOL -39 +#define DRWAV_PROTOCOL_UNAVAILABLE -40 +#define DRWAV_PROTOCOL_NOT_SUPPORTED -41 +#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRWAV_SOCKET_NOT_SUPPORTED -44 +#define DRWAV_CONNECTION_RESET -45 +#define DRWAV_ALREADY_CONNECTED -46 +#define DRWAV_NOT_CONNECTED -47 +#define DRWAV_CONNECTION_REFUSED -48 +#define DRWAV_NO_HOST -49 +#define DRWAV_IN_PROGRESS -50 +#define DRWAV_CANCELLED -51 +#define DRWAV_MEMORY_ALREADY_MAPPED -52 +#define DRWAV_AT_END -53 + +/* Common data formats. */ +#define DR_WAVE_FORMAT_PCM 0x1 +#define DR_WAVE_FORMAT_ADPCM 0x2 +#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 +#define DR_WAVE_FORMAT_ALAW 0x6 +#define DR_WAVE_FORMAT_MULAW 0x7 +#define DR_WAVE_FORMAT_DVI_ADPCM 0x11 +#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE + +/* Constants. */ +#ifndef DRWAV_MAX_SMPL_LOOPS +#define DRWAV_MAX_SMPL_LOOPS 1 +#endif + +/* Flags to pass into drwav_init_ex(), etc. */ +#define DRWAV_SEQUENTIAL 0x00000001 + +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision); +DRWAV_API const char* drwav_version_string(void); + +typedef enum +{ + drwav_seek_origin_start, + drwav_seek_origin_current +} drwav_seek_origin; + +typedef enum +{ + drwav_container_riff, + drwav_container_w64, + drwav_container_rf64 +} drwav_container; + +typedef struct +{ + union + { + drwav_uint8 fourcc[4]; + drwav_uint8 guid[16]; + } id; + + /* The size in bytes of the chunk. */ + drwav_uint64 sizeInBytes; + + /* + RIFF = 2 byte alignment. + W64 = 8 byte alignment. + */ + unsigned int paddingSize; +} drwav_chunk_header; + +typedef struct +{ + /* + The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications + that require support for data formats not natively supported by dr_wav. + */ + drwav_uint16 formatTag; + + /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */ + drwav_uint16 channels; + + /* The sample rate. Usually set to something like 44100. */ + drwav_uint32 sampleRate; + + /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */ + drwav_uint32 avgBytesPerSec; + + /* Block align. This is equal to the number of channels * bytes per sample. */ + drwav_uint16 blockAlign; + + /* Bits per sample. */ + drwav_uint16 bitsPerSample; + + /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */ + drwav_uint16 extendedSize; + + /* + The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, + is always rounded up to the nearest multiple of 8. This variable contains information about exactly how + many bits are valid per sample. Mainly used for informational purposes. + */ + drwav_uint16 validBitsPerSample; + + /* The channel mask. Not used at the moment. */ + drwav_uint32 channelMask; + + /* The sub-format, exactly as specified by the wave file. */ + drwav_uint8 subFormat[16]; +} drwav_fmt; + +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT); + + +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drwav_init() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +either the entire bytesToRead is filled or you have reached the end of the stream. +*/ +typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); + +/* +Callback for when data is written. Returns value is the number of bytes actually written. + +pUserData [in] The user data that was passed to drwav_init_write() and family. +pData [out] A pointer to the data to write. +bytesToWrite [in] The number of bytes to write. + +Returns the number of bytes actually written. + +If the return value differs from bytesToWrite, it indicates an error. +*/ +typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); + +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drwav_init() and family. +offset [in] The number of bytes to move, relative to the origin. Will never be negative. +origin [in] The origin of the seek - the current position or the start of the stream. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or +drwav_seek_origin_current. +*/ +typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); + +/* +Callback for when drwav_init_ex() finds a chunk. + +pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family. +onRead [in] A pointer to the function to call when reading. +onSeek [in] A pointer to the function to call when seeking. +pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family. +pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. +container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF. +pFMT [in] A pointer to the object containing the contents of the "fmt" chunk. + +Returns the number of bytes read + seeked. + +To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must +be the total number of bytes you have read _plus_ seeked. + +Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should +use `id.fourcc`, otherwise you should use `id.guid`. + +The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the +`DR_WAVE_FORMAT_*` identifiers. + +The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk. +*/ +typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT); + +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drwav_allocation_callbacks; + +/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */ +typedef struct +{ + const drwav_uint8* data; + size_t dataSize; + size_t currentReadPos; +} drwav__memory_stream; + +/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */ +typedef struct +{ + void** ppData; + size_t* pDataSize; + size_t dataSize; + size_t dataCapacity; + size_t currentWritePos; +} drwav__memory_stream_write; + +typedef struct +{ + drwav_container container; /* RIFF, W64. */ + drwav_uint32 format; /* DR_WAVE_FORMAT_* */ + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint32 bitsPerSample; +} drwav_data_format; + + +/* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */ +typedef struct +{ + drwav_uint32 cuePointId; + drwav_uint32 type; + drwav_uint32 start; + drwav_uint32 end; + drwav_uint32 fraction; + drwav_uint32 playCount; +} drwav_smpl_loop; + + typedef struct +{ + drwav_uint32 manufacturer; + drwav_uint32 product; + drwav_uint32 samplePeriod; + drwav_uint32 midiUnityNotes; + drwav_uint32 midiPitchFraction; + drwav_uint32 smpteFormat; + drwav_uint32 smpteOffset; + drwav_uint32 numSampleLoops; + drwav_uint32 samplerData; + drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS]; +} drwav_smpl; + +typedef struct +{ + /* A pointer to the function to call when more data is needed. */ + drwav_read_proc onRead; + + /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */ + drwav_write_proc onWrite; + + /* A pointer to the function to call when the wav file needs to be seeked. */ + drwav_seek_proc onSeek; + + /* The user data to pass to callbacks. */ + void* pUserData; + + /* Allocation callbacks. */ + drwav_allocation_callbacks allocationCallbacks; + + + /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */ + drwav_container container; + + + /* Structure containing format information exactly as specified by the wav file. */ + drwav_fmt fmt; + + /* The sample rate. Will be set to something like 44100. */ + drwav_uint32 sampleRate; + + /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */ + drwav_uint16 channels; + + /* The bits per sample. Will be set to something like 16, 24, etc. */ + drwav_uint16 bitsPerSample; + + /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */ + drwav_uint16 translatedFormatTag; + + /* The total number of PCM frames making up the audio data. */ + drwav_uint64 totalPCMFrameCount; + + + /* The size in bytes of the data chunk. */ + drwav_uint64 dataChunkDataSize; + + /* The position in the stream of the first byte of the data chunk. This is used for seeking. */ + drwav_uint64 dataChunkDataPos; + + /* The number of bytes remaining in the data chunk. */ + drwav_uint64 bytesRemaining; + + + /* + Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always + set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. + */ + drwav_uint64 dataChunkDataSizeTargetWrite; + + /* Keeps track of whether or not the wav writer was initialized in sequential mode. */ + drwav_bool32 isSequentialWrite; + + + /* smpl chunk. */ + drwav_smpl smpl; + + + /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */ + drwav__memory_stream memoryStream; + drwav__memory_stream_write memoryStreamWrite; + + /* Generic data for compressed formats. This data is shared across all block-compressed formats. */ + struct + { + drwav_uint64 iCurrentPCMFrame; /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */ + } compressed; + + /* Microsoft ADPCM specific data. */ + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_uint16 predictor[2]; + drwav_int32 delta[2]; + drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */ + drwav_uint32 cachedFrameCount; + drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */ + } msadpcm; + + /* IMA ADPCM specific data. */ + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_int32 predictor[2]; + drwav_int32 stepIndex[2]; + drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */ + drwav_uint32 cachedFrameCount; + } ima; +} drwav; + + +/* +Initializes a pre-allocated drwav object for reading. + +pWav [out] A pointer to the drwav object being initialized. +onRead [in] The function to call when data needs to be read from the client. +onSeek [in] The function to call when the read position of the client data needs to move. +onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. +pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. +flags [in, optional] A set of flags for controlling how things are loaded. + +Returns true if successful; false otherwise. + +Close the loader with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +to open the stream from a file or from a block of memory respectively. + +Possible values for flags: + DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function + to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. + +drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". + +The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt +after the function returns. + +See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() +*/ +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Initializes a pre-allocated drwav object for writing. + +onWrite [in] The function to call when data needs to be written. +onSeek [in] The function to call when the write position needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. + +Returns true if successful; false otherwise. + +Close the writer with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write() +to open the stream from a file or from a block of memory respectively. + +If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform +a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. + +See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() +*/ +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Utility function to determine the target size of the entire data to be written (including all headers and chunks). + +Returns the target size in bytes. + +Useful if the application needs to know the size to allocate. + +Only writing to the RIFF chunk and one data chunk is currently supported. + +See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write() +*/ +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); + +/* +Uninitializes the given drwav object. + +Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()). +*/ +DRWAV_API drwav_result drwav_uninit(drwav* pWav); + + +/* +Reads raw audio data. + +This is the lowest level function for reading audio data. It simply reads the given number of +bytes of the raw internal sample data. + +Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for +reading sample data in a consistent format. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of bytes actually read. +*/ +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); + +/* +Reads up to the specified number of PCM frames from the WAV file. + +The output data will be in the file's internal format, converted to native-endian byte order. Use +drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format. + +If the return value is less than it means the end of the file has been reached or +you have requested more PCM frames than can possibly fit in the output buffer. + +This function will only work when sample data is of a fixed size and uncompressed. If you are +using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32(). + +pBufferOut can be NULL in which case a seek will be performed. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); + +/* +Seeks to the given PCM frame. + +Returns true if successful; false otherwise. +*/ +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); + + +/* +Writes raw audio data. + +Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +*/ +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); + +/* +Writes PCM frames. + +Returns the number of PCM frames written. + +Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to +little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion. +*/ +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); + + +/* Conversion Utilities */ +#ifndef DR_WAV_NO_CONVERSION_API + +/* +Reads a chunk of audio data and converts it to signed 16-bit PCM samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +/* +Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +/* +Reads a chunk of audio data and converts it to signed 32-bit PCM samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +#endif /* DR_WAV_NO_CONVERSION_API */ + + +/* High-Level Convenience Helpers */ + +#ifndef DR_WAV_NO_STDIO +/* +Helper for initializing a wave file for reading using stdio. + +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Helper for initializing a wave file for writing using stdio. + +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif /* DR_WAV_NO_STDIO */ + +/* +Helper for initializing a loader from a pre-allocated memory buffer. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drwav object. + +The buffer should contain the contents of the entire wave file, not just the sample data. +*/ +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Helper for initializing a writer which outputs data to a memory buffer. + +dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). + +The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid +until after drwav_uninit() has been called. +*/ +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); + + +#ifndef DR_WAV_NO_CONVERSION_API +/* +Opens and reads an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_WAV_NO_STDIO +/* +Opens and decodes an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif +/* +Opens and decodes an entire wav file from a block of memory in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif + +/* Frees data that was allocated internally by dr_wav. */ +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* Converts bytes from a wav stream to a sized type of native endian. */ +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data); +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data); +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data); +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data); +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data); +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data); + +/* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */ +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]); + +/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */ +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); + +#ifdef __cplusplus +} +#endif +#endif /* dr_wav_h */ + + +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) +#ifndef dr_wav_c +#define dr_wav_c + +#include +#include /* For memcpy(), memset() */ +#include /* For INT_MAX */ + +#ifndef DR_WAV_NO_STDIO +#include +#include +#endif + +/* Standard library stuff. */ +#ifndef DRWAV_ASSERT +#include +#define DRWAV_ASSERT(expression) assert(expression) +#endif +#ifndef DRWAV_MALLOC +#define DRWAV_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRWAV_REALLOC +#define DRWAV_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRWAV_FREE +#define DRWAV_FREE(p) free((p)) +#endif +#ifndef DRWAV_COPY_MEMORY +#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRWAV_ZERO_MEMORY +#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#ifndef DRWAV_ZERO_OBJECT +#define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p)) +#endif + +#define drwav_countof(x) (sizeof(x) / sizeof(x[0])) +#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +#define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) +#define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) +#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) + +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ + +/* CPU architecture. */ +#if defined(__x86_64__) || defined(_M_X64) + #define DRWAV_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRWAV_X86 +#elif defined(__arm__) || defined(_M_ARM) + #define DRWAV_ARM +#endif + +#ifdef _MSC_VER + #define DRWAV_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRWAV_INLINE __inline__ __attribute__((always_inline)) + #else + #define DRWAV_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) + #define DRWAV_INLINE __inline +#else + #define DRWAV_INLINE +#endif + +#if defined(SIZE_MAX) + #define DRWAV_SIZE_MAX SIZE_MAX +#else + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRWAV_SIZE_MAX 0xFFFFFFFF + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #endif +#endif + +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision) +{ + if (pMajor) { + *pMajor = DRWAV_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = DRWAV_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRWAV_VERSION_REVISION; + } +} + +DRWAV_API const char* drwav_version_string(void) +{ + return DRWAV_VERSION_STRING; +} + +/* +These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are +you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation. +*/ +#ifndef DRWAV_MAX_SAMPLE_RATE +#define DRWAV_MAX_SAMPLE_RATE 384000 +#endif +#ifndef DRWAV_MAX_CHANNELS +#define DRWAV_MAX_CHANNELS 256 +#endif +#ifndef DRWAV_MAX_BITS_PER_SAMPLE +#define DRWAV_MAX_BITS_PER_SAMPLE 64 +#endif + +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */ +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ +/*static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ + +static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +{ + int i; + for (i = 0; i < 16; i += 1) { + if (a[i] != b[i]) { + return DRWAV_FALSE; + } + } + + return DRWAV_TRUE; +} + +static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const drwav_uint8* a, const char* b) +{ + return + a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + a[3] == b[3]; +} + + + +static DRWAV_INLINE int drwav__is_little_endian(void) +{ +#if defined(DRWAV_X86) || defined(DRWAV_X64) + return DRWAV_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRWAV_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} + +static DRWAV_INLINE drwav_uint16 drwav__bytes_to_u16(const drwav_uint8* data) +{ + return (data[0] << 0) | (data[1] << 8); +} + +static DRWAV_INLINE drwav_int16 drwav__bytes_to_s16(const drwav_uint8* data) +{ + return (short)drwav__bytes_to_u16(data); +} + +static DRWAV_INLINE drwav_uint32 drwav__bytes_to_u32(const drwav_uint8* data) +{ + return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +} + +static DRWAV_INLINE drwav_int32 drwav__bytes_to_s32(const drwav_uint8* data) +{ + return (drwav_int32)drwav__bytes_to_u32(data); +} + +static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const drwav_uint8* data) +{ + return + ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) | + ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56); +} + +static DRWAV_INLINE drwav_int64 drwav__bytes_to_s64(const drwav_uint8* data) +{ + return (drwav_int64)drwav__bytes_to_u64(data); +} + +static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) +{ + int i; + for (i = 0; i < 16; ++i) { + guid[i] = data[i]; + } +} + + +static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n) +{ +#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} + +static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n) +{ +#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ + /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ + drwav_uint32 r; + __asm__ __volatile__ ( + #if defined(DRWAV_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + +static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n) +{ +#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drwav_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drwav_uint64)0xFF000000 )) << 8) | + ((n & ((drwav_uint64)0x00FF0000 )) << 24) | + ((n & ((drwav_uint64)0x0000FF00 )) << 40) | + ((n & ((drwav_uint64)0x000000FF )) << 56); +#endif +} + + +static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n) +{ + return (drwav_int16)drwav__bswap16((drwav_uint16)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p) +{ + drwav_uint8 t; + t = p[0]; + p[0] = p[2]; + p[2] = t; +} + +static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + drwav_uint8* pSample = pSamples + (iSample*3); + drwav__bswap_s24(pSample); + } +} + + +static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n) +{ + return (drwav_int32)drwav__bswap32((drwav_uint32)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]); + } +} + + +static DRWAV_INLINE float drwav__bswap_f32(float n) +{ + union { + drwav_uint32 i; + float f; + } x; + x.f = n; + x.i = drwav__bswap32(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]); + } +} + + +static DRWAV_INLINE double drwav__bswap_f64(double n) +{ + union { + drwav_uint64 i; + double f; + } x; + x.f = n; + x.i = drwav__bswap64(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */ + switch (bytesPerSample) + { + case 2: /* s16, s12 (loosely packed) */ + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + case 3: /* s24 */ + { + drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); + } break; + case 4: /* s32 */ + { + drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + +static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + switch (bytesPerSample) + { + #if 0 /* Contributions welcome for f16 support. */ + case 2: /* f16 */ + { + drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount); + } break; + #endif + case 4: /* f32 */ + { + drwav__bswap_samples_f32((float*)pSamples, sampleCount); + } break; + case 8: /* f64 */ + { + drwav__bswap_samples_f64((double*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + +static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format) +{ + switch (format) + { + case DR_WAVE_FORMAT_PCM: + { + drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample); + } break; + + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample); + } break; + + case DR_WAVE_FORMAT_ALAW: + case DR_WAVE_FORMAT_MULAW: + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + + case DR_WAVE_FORMAT_ADPCM: + case DR_WAVE_FORMAT_DVI_ADPCM: + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + + +static void* drwav__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_MALLOC(sz); +} + +static void* drwav__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_REALLOC(p, sz); +} + +static void drwav__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRWAV_FREE(p); +} + + +static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } + + /* Try using realloc(). */ + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + + return NULL; +} + +static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); + } + + /* Try emulating realloc() in terms of malloc()/free(). */ + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + + if (p != NULL) { + DRWAV_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + /* Copy. */ + return *pAllocationCallbacks; + } else { + /* Defaults. */ + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drwav__malloc_default; + allocationCallbacks.onRealloc = drwav__realloc_default; + allocationCallbacks.onFree = drwav__free_default; + return allocationCallbacks; + } +} + + +static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) +{ + return + formatTag == DR_WAVE_FORMAT_ADPCM || + formatTag == DR_WAVE_FORMAT_DVI_ADPCM; +} + +static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 2); +} + +static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 8); +} + +static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); + +static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) +{ + if (container == drwav_container_riff || container == drwav_container_rf64) { + drwav_uint8 sizeInBytes[4]; + + if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 4) != 4) { + return DRWAV_INVALID_FILE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes); + pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 8; + } else { + drwav_uint8 sizeInBytes[8]; + + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 8) != 8) { + return DRWAV_INVALID_FILE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */ + pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 24; + } + + return DRWAV_SUCCESS; +} + +static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +{ + drwav_uint64 bytesRemainingToSeek = offset; + while (bytesRemainingToSeek > 0) { + if (bytesRemainingToSeek > 0x7FFFFFFF) { + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek -= 0x7FFFFFFF; + } else { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek = 0; + } + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +{ + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_start); + } + + /* Larger than 32-bit seek. */ + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + + for (;;) { + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_current); + } + + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + } + + /* Should never get here. */ + /*return DRWAV_TRUE; */ +} + + +static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) +{ + drwav_chunk_header header; + drwav_uint8 fmt[16]; + + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + + /* Skip non-fmt chunks. */ + while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { + if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; + + /* Try the next header. */ + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + } + + + /* Validation. */ + if (container == drwav_container_riff || container == drwav_container_rf64) { + if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { + return DRWAV_FALSE; + } + } else { + if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) { + return DRWAV_FALSE; + } + } + + + if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt); + + fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0); + fmtOut->channels = drwav__bytes_to_u16(fmt + 2); + fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4); + fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8); + fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12); + fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14); + + fmtOut->extendedSize = 0; + fmtOut->validBitsPerSample = 0; + fmtOut->channelMask = 0; + memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + + if (header.sizeInBytes > 16) { + drwav_uint8 fmt_cbSize[2]; + int bytesReadSoFar = 0; + + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { + return DRWAV_FALSE; /* Expecting more data. */ + } + *pRunningBytesReadOut += sizeof(fmt_cbSize); + + bytesReadSoFar = 18; + + fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize); + if (fmtOut->extendedSize > 0) { + /* Simple validation. */ + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + if (fmtOut->extendedSize != 22) { + return DRWAV_FALSE; + } + } + + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + drwav_uint8 fmtext[22]; + if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { + return DRWAV_FALSE; /* Expecting more data. */ + } + + fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0); + fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2); + drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); + } else { + if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + } + *pRunningBytesReadOut += fmtOut->extendedSize; + + bytesReadSoFar += fmtOut->extendedSize; + } + + /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ + if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); + } + + if (header.paddingSize > 0) { + if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.paddingSize; + } + + return DRWAV_TRUE; +} + + +static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) +{ + size_t bytesRead; + + DRWAV_ASSERT(onRead != NULL); + DRWAV_ASSERT(pCursor != NULL); + + bytesRead = onRead(pUserData, pBufferOut, bytesToRead); + *pCursor += bytesRead; + return bytesRead; +} + +#if 0 +static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor) +{ + DRWAV_ASSERT(onSeek != NULL); + DRWAV_ASSERT(pCursor != NULL); + + if (!onSeek(pUserData, offset, origin)) { + return DRWAV_FALSE; + } + + if (origin == drwav_seek_origin_start) { + *pCursor = offset; + } else { + *pCursor += offset; + } + + return DRWAV_TRUE; +} +#endif + + + +static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) +{ + /* + The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here + is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align. + */ + if ((pWav->bitsPerSample & 0x7) == 0) { + /* Bits per sample is a multiple of 8. */ + return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + } else { + return pWav->fmt.blockAlign; + } +} + +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) +{ + if (pFMT == NULL) { + return 0; + } + + if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) { + return pFMT->formatTag; + } else { + return drwav__bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */ + } +} + +static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pWav == NULL || onRead == NULL || onSeek == NULL) { + return DRWAV_FALSE; + } + + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onRead = onRead; + pWav->onSeek = onSeek; + pWav->pUserData = pReadSeekUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) +{ + /* This function assumes drwav_preinit() has been called beforehand. */ + + drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */ + drwav_bool32 sequential; + drwav_uint8 riff[4]; + drwav_fmt fmt; + unsigned short translatedFormatTag; + drwav_bool32 foundDataChunk; + drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */ + drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */ + drwav_uint64 chunkSize; + + cursor = 0; + sequential = (flags & DRWAV_SEQUENTIAL) != 0; + + /* The first 4 bytes should be the RIFF identifier. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { + return DRWAV_FALSE; + } + + /* + The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for + w64 it will start with "riff". + */ + if (drwav__fourcc_equal(riff, "RIFF")) { + pWav->container = drwav_container_riff; + } else if (drwav__fourcc_equal(riff, "riff")) { + int i; + drwav_uint8 riff2[12]; + + pWav->container = drwav_container_w64; + + /* Check the rest of the GUID for validity. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { + return DRWAV_FALSE; + } + + for (i = 0; i < 12; ++i) { + if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { + return DRWAV_FALSE; + } + } + } else if (drwav__fourcc_equal(riff, "RF64")) { + pWav->container = drwav_container_rf64; + } else { + return DRWAV_FALSE; /* Unknown or unsupported container. */ + } + + + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + drwav_uint8 chunkSizeBytes[4]; + drwav_uint8 wave[4]; + + /* RIFF/WAVE */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + if (pWav->container == drwav_container_riff) { + if (drwav__bytes_to_u32(chunkSizeBytes) < 36) { + return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */ + } + } else { + if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) { + return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */ + } + } + + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__fourcc_equal(wave, "WAVE")) { + return DRWAV_FALSE; /* Expecting "WAVE". */ + } + } else { + drwav_uint8 chunkSizeBytes[8]; + drwav_uint8 wave[16]; + + /* W64 */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + if (drwav__bytes_to_u64(chunkSizeBytes) < 80) { + return DRWAV_FALSE; + } + + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) { + return DRWAV_FALSE; + } + } + + + /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */ + if (pWav->container == drwav_container_rf64) { + drwav_uint8 sizeBytes[8]; + drwav_uint64 bytesRemainingInChunk; + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) { + return DRWAV_FALSE; /* Expecting "ds64". */ + } + + bytesRemainingInChunk = header.sizeInBytes + header.paddingSize; + + /* We don't care about the size of the RIFF chunk - skip it. */ + if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + cursor += 8; + + + /* Next 8 bytes is the size of the "data" chunk. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + dataChunkSize = drwav__bytes_to_u64(sizeBytes); + + + /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes); + + + /* Skip over everything else. */ + if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { + return DRWAV_FALSE; + } + cursor += bytesRemainingInChunk; + } + + + /* The next bytes should be the "fmt " chunk. */ + if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) { + return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */ + } + + /* Basic validation. */ + if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) || + (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) || + (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || + fmt.blockAlign == 0) { + return DRWAV_FALSE; /* Probably an invalid WAV file. */ + } + + + /* Translate the internal format. */ + translatedFormatTag = fmt.formatTag; + if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); + } + + + /* + We need to enumerate over each chunk for two reasons: + 1) The "data" chunk may not be the next one + 2) We may want to report each chunk back to the client + + In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. + */ + foundDataChunk = DRWAV_FALSE; + + /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */ + for (;;) + { + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + if (!foundDataChunk) { + return DRWAV_FALSE; + } else { + break; /* Probably at the end of the file. Get out of the loop. */ + } + } + + /* Tell the client about this chunk. */ + if (!sequential && onChunk != NULL) { + drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); + + /* + dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before + we called the callback. + */ + if (callbackBytesRead > 0) { + if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) { + return DRWAV_FALSE; + } + } + } + + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + + chunkSize = header.sizeInBytes; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav__fourcc_equal(header.id.fourcc, "data")) { + foundDataChunk = DRWAV_TRUE; + if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */ + dataChunkSize = chunkSize; + } + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) { + foundDataChunk = DRWAV_TRUE; + dataChunkSize = chunkSize; + } + } + + /* + If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for + this is that we would otherwise require a backwards seek which sequential mode forbids. + */ + if (foundDataChunk && sequential) { + break; + } + + /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */ + if (pWav->container == drwav_container_riff) { + if (drwav__fourcc_equal(header.id.fourcc, "fact")) { + drwav_uint32 sampleCount; + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { + return DRWAV_FALSE; + } + chunkSize -= 4; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + + /* + The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this + for Microsoft ADPCM formats. + */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + sampleCountFromFactChunk = sampleCount; + } else { + sampleCountFromFactChunk = 0; + } + } + } else if (pWav->container == drwav_container_w64) { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) { + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { + return DRWAV_FALSE; + } + chunkSize -= 8; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + } + } else if (pWav->container == drwav_container_rf64) { + /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */ + } + + /* "smpl" chunk. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav__fourcc_equal(header.id.fourcc, "smpl")) { + drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */ + if (chunkSize >= sizeof(smplHeaderData)) { + drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); + chunkSize -= bytesJustRead; + + if (bytesJustRead == sizeof(smplHeaderData)) { + drwav_uint32 iLoop; + + pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0); + pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4); + pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8); + pWav->smpl.midiUnityNotes = drwav__bytes_to_u32(smplHeaderData+12); + pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16); + pWav->smpl.smpteFormat = drwav__bytes_to_u32(smplHeaderData+20); + pWav->smpl.smpteOffset = drwav__bytes_to_u32(smplHeaderData+24); + pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28); + pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32); + + for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { + drwav_uint8 smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */ + bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor); + chunkSize -= bytesJustRead; + + if (bytesJustRead == sizeof(smplLoopData)) { + pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0); + pWav->smpl.loops[iLoop].type = drwav__bytes_to_u32(smplLoopData+4); + pWav->smpl.loops[iLoop].start = drwav__bytes_to_u32(smplLoopData+8); + pWav->smpl.loops[iLoop].end = drwav__bytes_to_u32(smplLoopData+12); + pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16); + pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20); + } else { + break; /* Break from the smpl loop for loop. */ + } + } + } + } else { + /* Looks like invalid data. Ignore the chunk. */ + } + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { + /* + This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution + is welcome to add support for this. + */ + } + } + + /* Make sure we seek past the padding. */ + chunkSize += header.paddingSize; + if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) { + break; + } + cursor += chunkSize; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + } + + /* If we haven't found a data chunk, return an error. */ + if (!foundDataChunk) { + return DRWAV_FALSE; + } + + /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */ + if (!sequential) { + if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { + return DRWAV_FALSE; + } + cursor = pWav->dataChunkDataPos; + } + + + /* At this point we should be sitting on the first byte of the raw audio data. */ + + pWav->fmt = fmt; + pWav->sampleRate = fmt.sampleRate; + pWav->channels = fmt.channels; + pWav->bitsPerSample = fmt.bitsPerSample; + pWav->bytesRemaining = dataChunkSize; + pWav->translatedFormatTag = translatedFormatTag; + pWav->dataChunkDataSize = dataChunkSize; + + if (sampleCountFromFactChunk != 0) { + pWav->totalPCMFrameCount = sampleCountFromFactChunk; + } else { + pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + + /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */ + pWav->totalPCMFrameCount += blockCount; + } + } + + /* Some formats only support a certain number of channels. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + if (pWav->channels > 2) { + return DRWAV_FALSE; + } + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + /* + I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), + it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count + from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct + way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should + always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my + correctness tests against libsndfile, and is disabled by default. + */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; + } +#endif + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); +} + + +static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize) +{ + drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + + return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */ +} + +static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) +{ + if (dataChunkSize <= 0xFFFFFFFFUL) { + return (drwav_uint32)dataChunkSize; + } else { + return 0xFFFFFFFFUL; + } +} + +static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); + + return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + + return chunkSize; +} + +static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + return dataChunkSize; +} + + +static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + /* Generic write. Assumes no byte reordering required. */ + return pWav->onWrite(pWav->pUserData, pData, dataSize); +} + +static size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap16(value); + } + + return drwav__write(pWav, &value, 2); +} + +static size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap32(value); + } + + return drwav__write(pWav, &value, 4); +} + +static size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap64(value); + } + + return drwav__write(pWav, &value, 8); +} + + +static drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pWav == NULL || onWrite == NULL) { + return DRWAV_FALSE; + } + + if (!isSequential && onSeek == NULL) { + return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */ + } + + /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */ + if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { + return DRWAV_FALSE; + } + if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) { + return DRWAV_FALSE; + } + + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onWrite = onWrite; + pWav->onSeek = onSeek; + pWav->pUserData = pUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + + pWav->fmt.formatTag = (drwav_uint16)pFormat->format; + pWav->fmt.channels = (drwav_uint16)pFormat->channels; + pWav->fmt.sampleRate = pFormat->sampleRate; + pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8); + pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8); + pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->fmt.extendedSize = 0; + pWav->isSequentialWrite = isSequential; + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) +{ + /* The function assumes drwav_preinit_write() was called beforehand. */ + + size_t runningPos = 0; + drwav_uint64 initialDataChunkSize = 0; + drwav_uint64 chunkSizeFMT; + + /* + The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In + sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- + sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. + */ + if (pWav->isSequentialWrite) { + initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; + + /* + The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 + so for the sake of simplicity I'm not doing any validation for that. + */ + if (pFormat->container == drwav_container_riff) { + if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { + return DRWAV_FALSE; /* Not enough room to store every sample. */ + } + } + } + + pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; + + + /* "RIFF" chunk. */ + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */ + runningPos += drwav__write(pWav, "RIFF", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, "WAVE", 4); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ + runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "RF64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */ + runningPos += drwav__write(pWav, "WAVE", 4); + } + + + /* "ds64" chunk (RF64 only). */ + if (pFormat->container == drwav_container_rf64) { + drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */ + drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */ + + runningPos += drwav__write(pWav, "ds64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */ + runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */ + } + + + /* "fmt " chunk. */ + if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) { + chunkSizeFMT = 16; + runningPos += drwav__write(pWav, "fmt ", 4); + runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT); + } else if (pFormat->container == drwav_container_w64) { + chunkSizeFMT = 40; + runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT); + } + + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample); + + pWav->dataChunkDataPos = runningPos; + + /* "data" chunk. */ + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ + runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */ + } + + /* + The runningPos variable is incremented in the section above but is left unused which is causing some static analysis tools to detect it + as a dead store. I'm leaving this as-is for safety just in case I want to expand this function later to include other tags and want to + keep track of the running position for whatever reason. The line below should silence the static analysis tools. + */ + (void)runningPos; + + /* Set some properties for the client's convenience. */ + pWav->container = pFormat->container; + pWav->channels = (drwav_uint16)pFormat->channels; + pWav->sampleRate = pFormat->sampleRate; + pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->translatedFormatTag = (drwav_uint16)pFormat->format; + + return DRWAV_TRUE; +} + + +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */ +} + +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */ +} + +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); +} + +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) +{ + /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */ + drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0); + drwav_uint64 riffChunkSizeBytes; + drwav_uint64 fileSizeBytes = 0; + + if (pFormat->container == drwav_container_riff) { + riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes); + fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ + } else if (pFormat->container == drwav_container_w64) { + riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes); + fileSizeBytes = riffChunkSizeBytes; + } else if (pFormat->container == drwav_container_rf64) { + riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes); + fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ + } + + return fileSizeBytes; +} + + +#ifndef DR_WAV_NO_STDIO + +/* drwav_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ +#include +static drwav_result drwav_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRWAV_SUCCESS; + #ifdef EPERM + case EPERM: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRWAV_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRWAV_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRWAV_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRWAV_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRWAV_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRWAV_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRWAV_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRWAV_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRWAV_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRWAV_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRWAV_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRWAV_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRWAV_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRWAV_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRWAV_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRWAV_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRWAV_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRWAV_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRWAV_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRWAV_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRWAV_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRWAV_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRWAV_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRWAV_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRWAV_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRWAV_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRWAV_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRWAV_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRWAV_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRWAV_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRWAV_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRWAV_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRWAV_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRWAV_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRWAV_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRWAV_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRWAV_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRWAV_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRWAV_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRWAV_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRWAV_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRWAV_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRWAV_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRWAV_ERROR; + #endif + #ifdef EADV + case EADV: return DRWAV_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRWAV_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRWAV_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRWAV_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRWAV_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRWAV_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRWAV_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRWAV_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRWAV_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRWAV_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRWAV_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRWAV_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRWAV_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRWAV_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRWAV_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRWAV_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRWAV_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRWAV_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRWAV_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRWAV_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRWAV_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRWAV_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRWAV_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRWAV_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRWAV_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRWAV_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRWAV_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRWAV_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRWAV_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRWAV_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRWAV_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRWAV_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRWAV_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRWAV_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRWAV_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRWAV_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRWAV_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRWAV_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRWAV_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRWAV_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRWAV_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRWAV_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRWAV_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRWAV_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRWAV_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRWAV_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRWAV_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRWAV_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRWAV_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRWAV_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRWAV_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRWAV_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRWAV_ERROR; + #endif + default: return DRWAV_ERROR; + } +} + +static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if _MSC_VER && _MSC_VER >= 1400 + errno_t err; +#endif + + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } + +#if _MSC_VER && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drwav_result result = drwav_result_from_errno(errno); + if (result == DRWAV_SUCCESS) { + result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRWAV_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRWAV_HAS_WFOPEN + #endif +#endif + +static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } + +#if defined(DRWAV_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drwav_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + DRWAV_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drwav_result_from_errno(errno); + } + + pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRWAV_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + DRWAV_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + + *ppFile = fopen(pFilePathMB, pOpenModeMB); + + drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + + if (*ppFile == NULL) { + return DRWAV_ERROR; + } +#endif + + return DRWAV_SUCCESS; +} + + +static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) +{ + return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); +} + +static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) +{ + return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; +} + +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); +} + + +static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav_bool32 result; + + result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); +} + + +static drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav_bool32 result; + + result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + result = drwav_init_write__internal(pWav, pFormat, totalSampleCount); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); +} + +static drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} +#endif /* DR_WAV_NO_STDIO */ + + +static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos); + + bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos; + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (bytesToRead > 0) { + DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); + pWav->memoryStream.currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { + return DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStream.currentReadPos < (size_t)-offset) { + return DRWAV_FALSE; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStream.currentReadPos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) { + pWav->memoryStream.currentReadPos = offset; + } else { + return DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); + + bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; + if (bytesRemaining < bytesToWrite) { + /* Need to reallocate. */ + void* pNewData; + size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2; + + /* If doubling wasn't enough, just make it the minimum required size to write the data. */ + if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) { + newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite; + } + + pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks); + if (pNewData == NULL) { + return 0; + } + + *pWav->memoryStreamWrite.ppData = pNewData; + pWav->memoryStreamWrite.dataCapacity = newDataCapacity; + } + + DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite); + + pWav->memoryStreamWrite.currentWritePos += bytesToWrite; + if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) { + pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos; + } + + *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize; + + return bytesToWrite; +} + +static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { + offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { + offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStreamWrite.currentWritePos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + pWav->memoryStreamWrite.currentWritePos = offset; + } else { + pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (data == NULL || dataSize == 0) { + return DRWAV_FALSE; + } + + if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + pWav->memoryStream.data = (const drwav_uint8*)data; + pWav->memoryStream.dataSize = dataSize; + pWav->memoryStream.currentReadPos = 0; + + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); +} + + +static drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (ppData == NULL || pDataSize == NULL) { + return DRWAV_FALSE; + } + + *ppData = NULL; /* Important because we're using realloc()! */ + *pDataSize = 0; + + if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + pWav->memoryStreamWrite.ppData = ppData; + pWav->memoryStreamWrite.pDataSize = pDataSize; + pWav->memoryStreamWrite.dataSize = 0; + pWav->memoryStreamWrite.dataCapacity = 0; + pWav->memoryStreamWrite.currentWritePos = 0; + + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} + + + +DRWAV_API drwav_result drwav_uninit(drwav* pWav) +{ + drwav_result result = DRWAV_SUCCESS; + + if (pWav == NULL) { + return DRWAV_INVALID_ARGS; + } + + /* + If the drwav object was opened in write mode we'll need to finalize a few things: + - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. + - Set the size of the "data" chunk. + */ + if (pWav->onWrite != NULL) { + drwav_uint32 paddingSize = 0; + + /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize); + } else { + paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize); + } + + if (paddingSize > 0) { + drwav_uint64 paddingData = 0; + drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */ + } + + /* + Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need + to do this when using non-sequential mode. + */ + if (pWav->onSeek && !pWav->isSequentialWrite) { + if (pWav->container == drwav_container_riff) { + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { + drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, riffChunkSize); + } + + /* the "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { + drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, dataChunkSize); + } + } else if (pWav->container == drwav_container_w64) { + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); + } + } else if (pWav->container == drwav_container_rf64) { + /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */ + int ds64BodyPos = 12 + 8; + + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); + } + } + } + + /* Validation for sequential mode. */ + if (pWav->isSequentialWrite) { + if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { + result = DRWAV_INVALID_FILE; + } + } + } + +#ifndef DR_WAV_NO_STDIO + /* + If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() + was used by looking at the onRead and onSeek callbacks. + */ + if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { + fclose((FILE*)pWav->pUserData); + } +#endif + + return result; +} + + + +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) +{ + size_t bytesRead; + + if (pWav == NULL || bytesToRead == 0) { + return 0; + } + + if (bytesToRead > pWav->bytesRemaining) { + bytesToRead = (size_t)pWav->bytesRemaining; + } + + if (pBufferOut != NULL) { + bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); + } else { + /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */ + bytesRead = 0; + while (bytesRead < bytesToRead) { + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > 0x7FFFFFFF) { + bytesToSeek = 0x7FFFFFFF; + } + + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) { + break; + } + + bytesRead += bytesToSeek; + } + + /* When we get here we may need to read-and-discard some data. */ + while (bytesRead < bytesToRead) { + drwav_uint8 buffer[4096]; + size_t bytesSeeked; + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > sizeof(buffer)) { + bytesToSeek = sizeof(buffer); + } + + bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek); + bytesRead += bytesSeeked; + + if (bytesSeeked < bytesToSeek) { + break; /* Reached the end. */ + } + } + } + + pWav->bytesRemaining -= bytesRead; + return bytesRead; +} + + + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + drwav_uint32 bytesPerFrame; + drwav_uint64 bytesToRead; /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */ + + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + /* Cannot use this function for compressed formats. */ + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + return 0; + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + bytesToRead = framesToRead * bytesPerFrame; + if (bytesToRead > DRWAV_SIZE_MAX) { + bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */ + } + + /* + Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There + *could* be a time where it evaluates to 0 due to overflowing. + */ + if (bytesToRead == 0) { + return 0; + } + + return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + + if (pBufferOut != NULL) { + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + if (drwav__is_little_endian()) { + return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + } else { + return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); + } +} + + + +DRWAV_API drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) +{ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; /* No seeking in write mode. */ + } + + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + pWav->compressed.iCurrentPCMFrame = 0; + + /* Cached data needs to be cleared for compressed formats. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->msadpcm); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->ima); + } else { + DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ + } + } + + pWav->bytesRemaining = pWav->dataChunkDataSize; + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) +{ + /* Seeking should be compatible with wave files > 2GB. */ + + if (pWav == NULL || pWav->onSeek == NULL) { + return DRWAV_FALSE; + } + + /* No seeking in write mode. */ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; + } + + /* If there are no samples, just return DRWAV_TRUE without doing anything. */ + if (pWav->totalPCMFrameCount == 0) { + return DRWAV_TRUE; + } + + /* Make sure the sample is clamped. */ + if (targetFrameIndex >= pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount - 1; + } + + /* + For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need + to seek back to the start. + */ + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + /* TODO: This can be optimized. */ + + /* + If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, + we first need to seek back to the start and then just do the same thing as a forward seek. + */ + if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) { + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; + } + } + + if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) { + drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame; + + drwav_int16 devnull[2048]; + while (offsetInFrames > 0) { + drwav_uint64 framesRead = 0; + drwav_uint64 framesToRead = offsetInFrames; + if (framesToRead > drwav_countof(devnull)/pWav->channels) { + framesToRead = drwav_countof(devnull)/pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull); + } else { + DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ + } + + if (framesRead != framesToRead) { + return DRWAV_FALSE; + } + + offsetInFrames -= framesRead; + } + } + } else { + drwav_uint64 totalSizeInBytes; + drwav_uint64 currentBytePos; + drwav_uint64 targetBytePos; + drwav_uint64 offset; + + totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); + + currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + + if (currentBytePos < targetBytePos) { + /* Offset forwards. */ + offset = (targetBytePos - currentBytePos); + } else { + /* Offset backwards. */ + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; + } + offset = targetBytePos; + } + + while (offset > 0) { + int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); + if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + + pWav->bytesRemaining -= offset32; + offset -= offset32; + } + } + + return DRWAV_TRUE; +} + + +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) +{ + size_t bytesWritten; + + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + pWav->dataChunkDataSize += bytesWritten; + + return bytesWritten; +} + + +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + const drwav_uint8* pRunningData; + + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { + return 0; + } + + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; + + while (bytesToWrite > 0) { + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; + + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ + + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + if (bytesJustWritten == 0) { + break; + } + + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; +} + +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + drwav_uint32 bytesPerSample; + const drwav_uint8* pRunningData; + + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { + return 0; + } + + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; + + bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + + while (bytesToWrite > 0) { + drwav_uint8 temp[4096]; + drwav_uint32 sampleCount; + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; + + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ + + /* + WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need + to use an intermediary buffer for the conversion. + */ + sampleCount = sizeof(temp)/bytesPerSample; + + if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) { + bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample; + } + + DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); + drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag); + + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); + if (bytesJustWritten == 0) { + break; + } + + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; +} + +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + if (drwav__is_little_endian()) { + return drwav_write_pcm_frames_le(pWav, framesToWrite, pData); + } else { + return drwav_write_pcm_frames_be(pWav, framesToWrite, pData); + } +} + + +static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead = 0; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + /* If there are no cached frames we need to load a new block. */ + if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + /* Mono. */ + drwav_uint8 header[7]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5); + pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; + pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.cachedFrameCount = 2; + } else { + /* Stereo. */ + drwav_uint8 header[14]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.predictor[1] = header[1]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2); + pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6); + pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10); + pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12); + + pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0]; + pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0]; + pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.cachedFrameCount = 2; + } + } + + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample = 0; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; + } + + pBufferOut += pWav->channels; + } + + framesToRead -= 1; + totalFramesRead += 1; + pWav->compressed.iCurrentPCMFrame += 1; + pWav->msadpcm.cachedFrameCount -= 1; + } + + if (framesToRead == 0) { + return totalFramesRead; + } + + + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->msadpcm.cachedFrameCount == 0) { + if (pWav->msadpcm.bytesRemainingInBlock == 0) { + continue; + } else { + static drwav_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + + drwav_uint8 nibbles; + drwav_int32 nibble0; + drwav_int32 nibble1; + + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + + /* TODO: Optimize away these if statements. */ + nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } + nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } + + if (pWav->channels == 1) { + /* Mono. */ + drwav_int32 newSample0; + drwav_int32 newSample1; + + newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; + + + newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[0]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample1; + + + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 2; + } else { + /* Stereo. */ + drwav_int32 newSample0; + drwav_int32 newSample1; + + /* Left. */ + newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; + + + /* Right. */ + newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[1]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; + if (pWav->msadpcm.delta[1] < 16) { + pWav->msadpcm.delta[1] = 16; + } + + pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.prevFrames[1][1] = newSample1; + + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 1; + } + } + } + } + + return totalFramesRead; +} + + +static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead = 0; + drwav_uint32 iChannel; + + static drwav_int32 indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + + static drwav_int32 stepTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + /* If there are no cached samples we need to load a new block. */ + if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + /* Mono. */ + drwav_uint8 header[4]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + if (header[2] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); + pWav->ima.bytesRemainingInBlock = 0; + return totalFramesRead; /* Invalid data. */ + } + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; + pWav->ima.cachedFrameCount = 1; + } else { + /* Stereo. */ + drwav_uint8 header[8]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); + pWav->ima.bytesRemainingInBlock = 0; + return totalFramesRead; /* Invalid data. */ + } + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4); + pWav->ima.stepIndex[1] = header[6]; + + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; + pWav->ima.cachedFrameCount = 1; + } + } + + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; + } + pBufferOut += pWav->channels; + } + + framesToRead -= 1; + totalFramesRead += 1; + pWav->compressed.iCurrentPCMFrame += 1; + pWav->ima.cachedFrameCount -= 1; + } + + if (framesToRead == 0) { + return totalFramesRead; + } + + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->ima.cachedFrameCount == 0) { + if (pWav->ima.bytesRemainingInBlock == 0) { + continue; + } else { + /* + From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the + left channel, 4 bytes for the right channel. + */ + pWav->ima.cachedFrameCount = 8; + for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { + drwav_uint32 iByte; + drwav_uint8 nibbles[4]; + if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { + pWav->ima.cachedFrameCount = 0; + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock -= 4; + + for (iByte = 0; iByte < 4; ++iByte) { + drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); + drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); + + drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; + drwav_int32 predictor = pWav->ima.predictor[iChannel]; + + drwav_int32 diff = step >> 3; + if (nibble0 & 1) diff += step >> 2; + if (nibble0 & 2) diff += step >> 1; + if (nibble0 & 4) diff += step; + if (nibble0 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor; + + + step = stepTable[pWav->ima.stepIndex[iChannel]]; + predictor = pWav->ima.predictor[iChannel]; + + diff = step >> 3; + if (nibble1 & 1) diff += step >> 2; + if (nibble1 & 2) diff += step >> 1; + if (nibble1 & 4) diff += step; + if (nibble1 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; + } + } + } + } + } + + return totalFramesRead; +} + + +#ifndef DR_WAV_NO_CONVERSION_API +static unsigned short g_drwavAlawTable[256] = { + 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, + 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, + 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, + 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, + 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, + 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, + 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, + 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, + 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, + 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, + 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, + 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, + 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, + 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, + 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, + 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 +}; + +static unsigned short g_drwavMulawTable[256] = { + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavAlawTable[sampleIn]; +} + +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavMulawTable[sampleIn]; +} + + + +static void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); + } +} + +static void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + +static drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint32 bytesPerFrame; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + /* Fast path. */ + if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x << 8; + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8; + r = x >> 8; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x >> 16; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + float c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5f); + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + double x = pIn[i]; + double c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5); + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__alaw_to_s16(pIn[i]); + } +} + +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__mulaw_to_s16(pIn[i]); + } +} + + + +static void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_f32(pOut, pIn, sampleCount); + return; + } + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_f32(pOut, pIn, sampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount); + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < sampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); + } +} + +static void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + unsigned int i; + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((const float*)pIn)[i]; + } + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } +} + + +static drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + /* Fast path. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + /* + It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears + libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note + the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated + correctness testing. This is disabled by default. + */ + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (pIn[i] / 256.0f) * 2 - 1; + } +#else + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ + + *pOut++ = x; + } +#endif +} + +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] * 0.000030517578125f; + } +} + +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + double x; + drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) << 8); + drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16); + drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24); + + x = (double)((drwav_int32)(a | b | c) >> 8); + *pOut++ = (float)(x * 0.00000011920928955078125); + } +} + +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)(pIn[i] / 2147483648.0); + } +} + +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)pIn[i]; + } +} + +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; + } +} + +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; + } +} + + + +static void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_s32(pOut, pIn, totalSampleCount); + return; + } + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s32(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int32*)pIn)[i]; + } + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); + } +} + +static void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + + +static drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + /* Fast path. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((int)pIn[i] - 128) << 24; + } +} + +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] << 16; + } +} + +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + unsigned int s0 = pIn[i*3 + 0]; + unsigned int s1 = pIn[i*3 + 1]; + unsigned int s2 = pIn[i*3 + 2]; + + drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); + *pOut++ = sample32; + } +} + +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; + } +} + +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i= 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; + } +} + + + +static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + drwav_int16* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + +static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + float* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + +static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + drwav_int32* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + + + +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +#ifndef DR_WAV_NO_STDIO +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + + +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif + +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif /* DR_WAV_NO_CONVERSION_API */ + + +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drwav__free_from_callbacks(p, pAllocationCallbacks); + } else { + drwav__free_default(p, NULL); + } +} + +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) +{ + return drwav__bytes_to_u16(data); +} + +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) +{ + return drwav__bytes_to_s16(data); +} + +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data) +{ + return drwav__bytes_to_u32(data); +} + +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) +{ + return drwav__bytes_to_s32(data); +} + +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data) +{ + return drwav__bytes_to_u64(data); +} + +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data) +{ + return drwav__bytes_to_s64(data); +} + + +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +{ + return drwav__guid_equal(a, b); +} + +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) +{ + return drwav__fourcc_equal(a, b); +} + +#endif /* dr_wav_c */ +#endif /* DR_WAV_IMPLEMENTATION */ + +/* +RELEASE NOTES - v0.11.0 +======================= +Version 0.11.0 has breaking API changes. + +Improved Client-Defined Memory Allocation +----------------------------------------- +The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The +existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom +allocation callbacks are specified. + +To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this: + + void* my_malloc(size_t sz, void* pUserData) + { + return malloc(sz); + } + void* my_realloc(void* p, size_t sz, void* pUserData) + { + return realloc(p, sz); + } + void my_free(void* p, void* pUserData) + { + free(p); + } + + ... + + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drwav_init_file(&wav, "my_file.wav", &allocationCallbacks); + +The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines. + +Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC, +DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drwav object now takes this extra parameter. These include the following: + + drwav_init() + drwav_init_ex() + drwav_init_file() + drwav_init_file_ex() + drwav_init_file_w() + drwav_init_file_w_ex() + drwav_init_memory() + drwav_init_memory_ex() + drwav_init_write() + drwav_init_write_sequential() + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write() + drwav_init_file_write_sequential() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write() + drwav_init_memory_write_sequential() + drwav_init_memory_write_sequential_pcm_frames() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_pcm_frames_s32() + +Endian Improvements +------------------- +Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility +on big-endian architectures. + + drwav_read_pcm_frames() + drwav_read_pcm_frames_s16() + drwav_read_pcm_frames_s32() + drwav_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_s32() + drwav_open_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_s32() + drwav_open_memory_and_read_pcm_frames_f32() + +APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte +order: + + drwav_read_pcm_frames_le() + drwav_read_pcm_frames_be() + drwav_read_pcm_frames_s16le() + drwav_read_pcm_frames_s16be() + drwav_read_pcm_frames_f32le() + drwav_read_pcm_frames_f32be() + drwav_read_pcm_frames_s32le() + drwav_read_pcm_frames_s32be() + drwav_write_pcm_frames_le() + drwav_write_pcm_frames_be() + +Removed APIs +------------ +The following APIs were deprecated in version 0.10.0 and have now been removed: + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + + + +RELEASE NOTES - v0.10.0 +======================= +Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do +not need to upgrade. + +Removed APIs +------------ +The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0: + + drwav_read() + drwav_read_s16() + drwav_read_f32() + drwav_read_s32() + drwav_seek_to_sample() + drwav_write() + drwav_open_and_read_s16() + drwav_open_and_read_f32() + drwav_open_and_read_s32() + drwav_open_file_and_read_s16() + drwav_open_file_and_read_f32() + drwav_open_file_and_read_s32() + drwav_open_memory_and_read_s16() + drwav_open_memory_and_read_f32() + drwav_open_memory_and_read_s32() + drwav::totalSampleCount + +See release notes for version 0.9.0 at the bottom of this file for replacement APIs. + +Deprecated APIs +--------------- +The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and +drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a +drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre- +allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by +a called to one of the drwav_init*() APIs. + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + +These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the +two different ways to initialize a drwav object. +*/ + +/* +REVISION HISTORY +================ +v0.12.16 - 2020-12-02 + - Fix a bug when trying to read more bytes than can fit in a size_t. + +v0.12.15 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.14 - 2020-11-13 + - Minor code clean up. + +v0.12.13 - 2020-11-01 + - Improve compiler support for older versions of GCC. + +v0.12.12 - 2020-09-28 + - Add support for RF64. + - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section. + +v0.12.11 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.10 - 2020-08-24 + - Fix a bug when seeking with ADPCM formats. + +v0.12.9 - 2020-08-02 + - Simplify sized types. + +v0.12.8 - 2020-07-25 + - Fix a compilation warning. + +v0.12.7 - 2020-07-15 + - Fix some bugs on big-endian architectures. + - Fix an error in s24 to f32 conversion. + +v0.12.6 - 2020-06-23 + - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek. + - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files. + - Add include guard for the implementation section. + +v0.12.5 - 2020-05-27 + - Minor documentation fix. + +v0.12.4 - 2020-05-16 + - Replace assert() with DRWAV_ASSERT(). + - Add compile-time and run-time version querying. + - DRWAV_VERSION_MINOR + - DRWAV_VERSION_MAJOR + - DRWAV_VERSION_REVISION + - DRWAV_VERSION_STRING + - drwav_version() + - drwav_version_string() + +v0.12.3 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.2 - 2020-04-21 + - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file. + +v0.12.1 - 2020-04-13 + - Fix some pedantic warnings. + +v0.12.0 - 2020-04-04 + - API CHANGE: Add container and format parameters to the chunk callback. + - Minor documentation updates. + +v0.11.5 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.11.4 - 2020-01-29 + - Fix some static analysis warnings. + - Fix a bug when reading f32 samples from an A-law encoded stream. + +v0.11.3 - 2020-01-12 + - Minor changes to some f32 format conversion routines. + - Minor bug fix for ADPCM conversion when end of file is reached. + +v0.11.2 - 2019-12-02 + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix an integer overflow bug. + - Fix a null pointer dereference bug. + - Add limits to sample rate, channels and bits per sample to tighten up some validation. + +v0.11.1 - 2019-10-07 + - Internal code clean up. + +v0.11.0 - 2019-10-06 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drwav_init() + - drwav_init_ex() + - drwav_init_file() + - drwav_init_file_ex() + - drwav_init_file_w() + - drwav_init_file_w_ex() + - drwav_init_memory() + - drwav_init_memory_ex() + - drwav_init_write() + - drwav_init_write_sequential() + - drwav_init_write_sequential_pcm_frames() + - drwav_init_file_write() + - drwav_init_file_write_sequential() + - drwav_init_file_write_sequential_pcm_frames() + - drwav_init_file_write_w() + - drwav_init_file_write_sequential_w() + - drwav_init_file_write_sequential_pcm_frames_w() + - drwav_init_memory_write() + - drwav_init_memory_write_sequential() + - drwav_init_memory_write_sequential_pcm_frames() + - drwav_open_and_read_pcm_frames_s16() + - drwav_open_and_read_pcm_frames_f32() + - drwav_open_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_s16() + - drwav_open_file_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_s16_w() + - drwav_open_file_and_read_pcm_frames_f32_w() + - drwav_open_file_and_read_pcm_frames_s32_w() + - drwav_open_memory_and_read_pcm_frames_s16() + - drwav_open_memory_and_read_pcm_frames_f32() + - drwav_open_memory_and_read_pcm_frames_s32() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE. + - Add support for reading and writing PCM frames in an explicit endianness. New APIs: + - drwav_read_pcm_frames_le() + - drwav_read_pcm_frames_be() + - drwav_read_pcm_frames_s16le() + - drwav_read_pcm_frames_s16be() + - drwav_read_pcm_frames_f32le() + - drwav_read_pcm_frames_f32be() + - drwav_read_pcm_frames_s32le() + - drwav_read_pcm_frames_s32be() + - drwav_write_pcm_frames_le() + - drwav_write_pcm_frames_be() + - Remove deprecated APIs. + - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data. + - drwav_read_pcm_frames() + - drwav_read_pcm_frames_s16() + - drwav_read_pcm_frames_s32() + - drwav_read_pcm_frames_f32() + - drwav_open_and_read_pcm_frames_s16() + - drwav_open_and_read_pcm_frames_s32() + - drwav_open_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s16() + - drwav_open_file_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s16_w() + - drwav_open_file_and_read_pcm_frames_s32_w() + - drwav_open_file_and_read_pcm_frames_f32_w() + - drwav_open_memory_and_read_pcm_frames_s16() + - drwav_open_memory_and_read_pcm_frames_s32() + - drwav_open_memory_and_read_pcm_frames_f32() + +v0.10.1 - 2019-08-31 + - Correctly handle partial trailing ADPCM blocks. + +v0.10.0 - 2019-08-04 + - Remove deprecated APIs. + - Add wchar_t variants for file loading APIs: + drwav_init_file_w() + drwav_init_file_ex_w() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count. + - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode: + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write_sequential_pcm_frames() + - Deprecate drwav_open*() and drwav_close(): + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + - Minor documentation updates. + +v0.9.2 - 2019-05-21 + - Fix warnings. + +v0.9.1 - 2019-05-05 + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.9.0 - 2018-12-16 + - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and + will be removed in v0.10.0. Deprecated APIs and their replacements: + drwav_read() -> drwav_read_pcm_frames() + drwav_read_s16() -> drwav_read_pcm_frames_s16() + drwav_read_f32() -> drwav_read_pcm_frames_f32() + drwav_read_s32() -> drwav_read_pcm_frames_s32() + drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() + drwav_write() -> drwav_write_pcm_frames() + drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() + drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() + drwav::totalSampleCount -> drwav::totalPCMFrameCount + - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). + - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). + - Add built-in support for smpl chunks. + - Add support for firing a callback for each chunk in the file at initialization time. + - This is enabled through the drwav_init_ex(), etc. family of APIs. + - Handle invalid FMT chunks more robustly. + +v0.8.5 - 2018-09-11 + - Const correctness. + - Fix a potential stack overflow. + +v0.8.4 - 2018-08-07 + - Improve 64-bit detection. + +v0.8.3 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.8.2 - 2018-08-02 + - Fix some big-endian bugs. + +v0.8.1 - 2018-06-29 + - Add support for sequential writing APIs. + - Disable seeking in write mode. + - Fix bugs with Wave64. + - Fix typos. + +v0.8 - 2018-04-27 + - Bug fix. + - Start using major.minor.revision versioning. + +v0.7f - 2018-02-05 + - Restrict ADPCM formats to a maximum of 2 channels. + +v0.7e - 2018-02-02 + - Fix a crash. + +v0.7d - 2018-02-01 + - Fix a crash. + +v0.7c - 2018-02-01 + - Set drwav.bytesPerSample to 0 for all compressed formats. + - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for + all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). + - Fix some divide-by-zero errors. + +v0.7b - 2018-01-22 + - Fix errors with seeking of compressed formats. + - Fix compilation error when DR_WAV_NO_CONVERSION_API + +v0.7a - 2017-11-17 + - Fix some GCC warnings. + +v0.7 - 2017-11-04 + - Add writing APIs. + +v0.6 - 2017-08-16 + - API CHANGE: Rename dr_* types to drwav_*. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add support for Microsoft ADPCM. + - Add support for IMA ADPCM (DVI, format code 0x11). + - Optimizations to drwav_read_s16(). + - Bug fixes. + +v0.5g - 2017-07-16 + - Change underlying type for booleans to unsigned. + +v0.5f - 2017-04-04 + - Fix a minor bug with drwav_open_and_read_s16() and family. + +v0.5e - 2016-12-29 + - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. + - Minor fixes to documentation. + +v0.5d - 2016-12-28 + - Use drwav_int* and drwav_uint* sized types to improve compiler support. + +v0.5c - 2016-11-11 + - Properly handle JUNK chunks that come before the FMT chunk. + +v0.5b - 2016-10-23 + - A minor change to drwav_bool8 and drwav_bool32 types. + +v0.5a - 2016-10-11 + - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. + - Improve A-law and mu-law efficiency. + +v0.5 - 2016-09-29 + - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to + keep it consistent with dr_audio and dr_flac. + +v0.4b - 2016-09-18 + - Fixed a typo in documentation. + +v0.4a - 2016-09-18 + - Fixed a typo. + - Change date format to ISO 8601 (YYYY-MM-DD) + +v0.4 - 2016-07-13 + - API CHANGE. Make onSeek consistent with dr_flac. + - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. + - Added support for Sony Wave64. + +v0.3a - 2016-05-28 + - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. + - Fixed a memory leak. + +v0.3 - 2016-05-22 + - Lots of API changes for consistency. + +v0.2a - 2016-05-16 + - Fixed Linux/GCC build. + +v0.2 - 2016-05-11 + - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. + +v0.1a - 2016-05-07 + - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. + +v0.1 - 2016-05-04 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== +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 + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2020 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +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 OR COPYRIGHT HOLDERS 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. +*/ diff --git a/examples/ffmpeg-transcode.cpp b/examples/ffmpeg-transcode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f800db66d55e08e6c0678970f19dd6cc64c69e6c --- /dev/null +++ b/examples/ffmpeg-transcode.cpp @@ -0,0 +1,350 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * transcode.c - convert audio file to WAVE + * + * Copyright (C) 2019 Andrew Clayton + * Copyright (C) 2024 William Tambellini + */ + +// Just for conveninent C++ API +#include +#include + +// C +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +} + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint8_t u8; +typedef int8_t s8; + +#define WAVE_SAMPLE_RATE 16000 +#define AVIO_CTX_BUF_SZ 4096 + +static const char* ffmpegLog = getenv("FFMPEG_LOG"); +// Todo: add __FILE__ __LINE__ +#define LOG(...) \ + do { if (ffmpegLog) fprintf(stderr, __VA_ARGS__); } while(0) // C99 + +/* + * WAVE file header based on definition from + * https://gist.github.com/Jon-Schneider/8b7c53d27a7a13346a643dac9c19d34f + * + * We must ensure this structure doesn't have any holes or + * padding so we can just map it straight to the WAVE data. + */ +struct wave_hdr { + /* RIFF Header: "RIFF" */ + char riff_header[4]; + /* size of audio data + sizeof(struct wave_hdr) - 8 */ + int wav_size; + /* "WAVE" */ + char wav_header[4]; + + /* Format Header */ + /* "fmt " (includes trailing space) */ + char fmt_header[4]; + /* Should be 16 for PCM */ + int fmt_chunk_size; + /* Should be 1 for PCM. 3 for IEEE Float */ + s16 audio_format; + s16 num_channels; + int sample_rate; + /* + * Number of bytes per second + * sample_rate * num_channels * bit_depth/8 + */ + int byte_rate; + /* num_channels * bytes per sample */ + s16 sample_alignment; + /* bits per sample */ + s16 bit_depth; + + /* Data Header */ + /* "data" */ + char data_header[4]; + /* + * size of audio + * number of samples * num_channels * bit_depth/8 + */ + int data_bytes; +} __attribute__((__packed__)); + +struct audio_buffer { + u8 *ptr; + int size; /* size left in the buffer */ +}; + +static void set_wave_hdr(wave_hdr& wh, size_t size) { + memcpy(&wh.riff_header, "RIFF", 4); + wh.wav_size = size + sizeof(struct wave_hdr) - 8; + memcpy(&wh.wav_header, "WAVE", 4); + memcpy(&wh.fmt_header, "fmt ", 4); + wh.fmt_chunk_size = 16; + wh.audio_format = 1; + wh.num_channels = 1; + wh.sample_rate = WAVE_SAMPLE_RATE; + wh.sample_alignment = 2; + wh.bit_depth = 16; + wh.byte_rate = wh.sample_rate * wh.sample_alignment; + memcpy(&wh.data_header, "data", 4); + wh.data_bytes = size; +} + +static void write_wave_hdr(int fd, size_t size) { + struct wave_hdr wh; + set_wave_hdr(wh, size); + write(fd, &wh, sizeof(struct wave_hdr)); +} + +static int map_file(int fd, u8 **ptr, size_t *size) +{ + struct stat sb; + + fstat(fd, &sb); + *size = sb.st_size; + + *ptr = (u8*)mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (*ptr == MAP_FAILED) { + perror("mmap"); + return -1; + } + + return 0; +} + +static int read_packet(void *opaque, u8 *buf, int buf_size) +{ + struct audio_buffer *audio_buf = (audio_buffer*)opaque; + + buf_size = FFMIN(buf_size, audio_buf->size); + + /* copy internal buffer data to buf */ + memcpy(buf, audio_buf->ptr, buf_size); + audio_buf->ptr += buf_size; + audio_buf->size -= buf_size; + + return buf_size; +} + +static void convert_frame(struct SwrContext *swr, AVCodecContext *codec, + AVFrame *frame, s16 **data, int *size, bool flush) +{ + int nr_samples; + s64 delay; + u8 *buffer; + + delay = swr_get_delay(swr, codec->sample_rate); + nr_samples = av_rescale_rnd(delay + frame->nb_samples, + WAVE_SAMPLE_RATE, codec->sample_rate, + AV_ROUND_UP); + av_samples_alloc(&buffer, NULL, 1, nr_samples, AV_SAMPLE_FMT_S16, 0); + + /* + * !flush is used to check if we are flushing any remaining + * conversion buffers... + */ + nr_samples = swr_convert(swr, &buffer, nr_samples, + !flush ? (const u8 **)frame->data : NULL, + !flush ? frame->nb_samples : 0); + + *data = (s16*)realloc(*data, (*size + nr_samples) * sizeof(s16)); + memcpy(*data + *size, buffer, nr_samples * sizeof(s16)); + *size += nr_samples; + av_freep(&buffer); +} + +static bool is_audio_stream(const AVStream *stream) +{ + if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + return true; + + return false; +} + +// Return non zero on error, 0 on success +// audio_buffer: input memory +// data: decoded output audio data (wav file) +// size: size of output data +static int decode_audio(struct audio_buffer *audio_buf, s16 **data, int *size) +{ + LOG("decode_audio: input size: %d\n", audio_buf->size); + AVFormatContext *fmt_ctx; + AVIOContext *avio_ctx; + AVStream *stream; + AVCodecContext *codec; + AVPacket packet; + AVFrame *frame; + struct SwrContext *swr; + u8 *avio_ctx_buffer; + unsigned int i; + int stream_index = -1; + int err; + const size_t errbuffsize = 1024; + char errbuff[errbuffsize]; + + av_register_all(); // from avformat. Still a must-have call for ffmpeg v3! (can be skipped for later versions) + + fmt_ctx = avformat_alloc_context(); + avio_ctx_buffer = (u8*)av_malloc(AVIO_CTX_BUF_SZ); + LOG("Creating an avio context: AVIO_CTX_BUF_SZ=%d\n", AVIO_CTX_BUF_SZ); + avio_ctx = avio_alloc_context(avio_ctx_buffer, AVIO_CTX_BUF_SZ, 0, audio_buf, &read_packet, NULL, NULL); + fmt_ctx->pb = avio_ctx; + + // open the input stream and read header + err = avformat_open_input(&fmt_ctx, NULL, NULL, NULL); + if (err) { + LOG("Could not read audio buffer: %d: %s\n", err, av_make_error_string(errbuff, errbuffsize, err)); + return err; + } + + err = avformat_find_stream_info(fmt_ctx, NULL); + if (err < 0) { + LOG("Could not retrieve stream info from audio buffer: %d\n", err); + return err; + } + + for (i = 0; i < fmt_ctx->nb_streams; i++) { + if (is_audio_stream(fmt_ctx->streams[i])) { + stream_index = i; + break; + } + } + + if (stream_index == -1) { + LOG("Could not retrieve audio stream from buffer\n"); + return -1; + } + + stream = fmt_ctx->streams[stream_index]; + codec = avcodec_alloc_context3( + avcodec_find_decoder(stream->codecpar->codec_id)); + avcodec_parameters_to_context(codec, stream->codecpar); + err = avcodec_open2(codec, avcodec_find_decoder(codec->codec_id), + NULL); + if (err) { + LOG("Failed to open decoder for stream #%d in audio buffer\n", stream_index); + return err; + } + + /* prepare resampler */ + swr = swr_alloc(); + + av_opt_set_int(swr, "in_channel_count", codec->channels, 0); + av_opt_set_int(swr, "out_channel_count", 1, 0); + av_opt_set_int(swr, "in_channel_layout", codec->channel_layout, 0); + av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0); + av_opt_set_int(swr, "in_sample_rate", codec->sample_rate, 0); + av_opt_set_int(swr, "out_sample_rate", WAVE_SAMPLE_RATE, 0); + av_opt_set_sample_fmt(swr, "in_sample_fmt", codec->sample_fmt, 0); + av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + + swr_init(swr); + if (!swr_is_initialized(swr)) { + LOG("Resampler has not been properly initialized\n"); + return -1; + } + + av_init_packet(&packet); + frame = av_frame_alloc(); + if (!frame) { + LOG("Error allocating the frame\n"); + return -1; + } + + /* iterate through frames */ + *data = NULL; + *size = 0; + while (av_read_frame(fmt_ctx, &packet) >= 0) { + avcodec_send_packet(codec, &packet); + + err = avcodec_receive_frame(codec, frame); + if (err == AVERROR(EAGAIN)) + continue; + + convert_frame(swr, codec, frame, data, size, false); + } + /* Flush any remaining conversion buffers... */ + convert_frame(swr, codec, frame, data, size, true); + + av_frame_free(&frame); + swr_free(&swr); + //avio_context_free(); // todo? + avcodec_close(codec); + avformat_close_input(&fmt_ctx); + avformat_free_context(fmt_ctx); + + if (avio_ctx) { + av_freep(&avio_ctx->buffer); + av_freep(&avio_ctx); + } + + return 0; +} + +// in mem decoding/conversion/resampling: +// ifname: input file path +// owav_data: in mem wav file. Can be forwarded as it to whisper/drwav +// return 0 on success +int ffmpeg_decode_audio(const std::string &ifname, std::vector& owav_data) { + LOG("ffmpeg_decode_audio: %s\n", ifname.c_str()); + int ifd = open(ifname.c_str(), O_RDONLY); + if (ifd == -1) { + fprintf(stderr, "Couldn't open input file %s\n", ifname.c_str()); + return -1; + } + u8 *ibuf = NULL; + size_t ibuf_size; + int err = map_file(ifd, &ibuf, &ibuf_size); + if (err) { + LOG("Couldn't map input file %s\n", ifname.c_str()); + return err; + } + LOG("Mapped input file: %s size: %d\n", ibuf, (int) ibuf_size); + struct audio_buffer inaudio_buf; + inaudio_buf.ptr = ibuf; + inaudio_buf.size = ibuf_size; + + s16 *odata=NULL; + int osize=0; + + err = decode_audio(&inaudio_buf, &odata, &osize); + LOG("decode_audio returned %d \n", err); + if (err != 0) { + LOG("decode_audio failed\n"); + return err; + } + LOG("decode_audio output size: %d\n", osize); + + wave_hdr wh; + const size_t outdatasize = osize * sizeof(s16); + set_wave_hdr(wh, outdatasize); + owav_data.resize(sizeof(wave_hdr) + outdatasize); + // header: + memcpy(owav_data.data(), &wh, sizeof(wave_hdr)); + // the data: + memcpy(owav_data.data() + sizeof(wave_hdr), odata, osize* sizeof(s16)); + + return 0; +} diff --git a/examples/generate-karaoke.sh b/examples/generate-karaoke.sh new file mode 100644 index 0000000000000000000000000000000000000000..7062c9a0850a397d83748dd0b9dda01024f41fcc --- /dev/null +++ b/examples/generate-karaoke.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Simple tool to record audio from the microphone and generate a karaoke video +# Usage: +# +# cd whisper.cpp +# make +# +# ./examples/generate-karaoke.sh [model] [step_ms] +# +# Press Ctrl+C to stop recording +# + +executable="./main" +model="base.en" +model_path="models/ggml-$model.bin" + +# require sox and ffmpeg to be installed +if ! command -v sox &> /dev/null +then + echo "sox could not be found" + exit 1 +fi + +if ! command -v ffmpeg &> /dev/null +then + echo "ffmpeg could not be found" + exit 2 +fi + +if [ ! -f "$executable" ]; then + echo "'$executable' does not exist. Please build it first." + exit 3 +fi + +if [ ! -f "$model_path" ]; then + echo "'$model_path' does not exist. Please download it first." + exit 4 +fi + +# record some raw audio +sox -d rec.wav + +# resample to 16kHz +ffmpeg -y -i ./rec.wav -ar 16000 -ac 1 -c:a pcm_s16le ./rec16.wav > /dev/null 2>&1 + +# run Whisper +echo "Processing ..." +./main -m models/ggml-base.en.bin rec16.wav -owts > /dev/null 2>&1 + +# generate Karaoke video +echo "Generating video ..." +source rec16.wav.wts > /dev/null 2>&1 + +# play the video +echo "Playing ./rec16.wav.mp4 ..." +ffplay -loglevel 0 -autoexit ./rec16.wav.mp4 + +echo "Done" +exit 0 diff --git a/examples/grammar-parser.cpp b/examples/grammar-parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e282fc7bf56169831f18c11afe64c28dd9203903 --- /dev/null +++ b/examples/grammar-parser.cpp @@ -0,0 +1,423 @@ +#include "grammar-parser.h" +#include +#include +#include +#include +#include +#include + +namespace grammar_parser { + // NOTE: assumes valid utf8 (but checks for overrun) + // copied from whisper.cpp + static std::pair decode_utf8(const char * src) { + static const int lookup[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4 }; + uint8_t first_byte = static_cast(*src); + uint8_t highbits = first_byte >> 4; + int len = lookup[highbits]; + uint8_t mask = (1 << (8 - len)) - 1; + uint32_t value = first_byte & mask; + const char * end = src + len; // may overrun! + const char * pos = src + 1; + for ( ; pos < end && *pos; pos++) { + value = (value << 6) + (static_cast(*pos) & 0x3F); + } + return std::make_pair(value, pos); + } + + static uint32_t get_symbol_id(parse_state & state, const char * src, size_t len) { + uint32_t next_id = static_cast(state.symbol_ids.size()); + auto result = state.symbol_ids.insert(std::make_pair(std::string(src, len), next_id)); + return result.first->second; + } + + static uint32_t generate_symbol_id(parse_state & state, const std::string & base_name) { + uint32_t next_id = static_cast(state.symbol_ids.size()); + state.symbol_ids[base_name + '_' + std::to_string(next_id)] = next_id; + return next_id; + } + + static void add_rule( + parse_state & state, + uint32_t rule_id, + const std::vector & rule) { + if (state.rules.size() <= rule_id) { + state.rules.resize(rule_id + 1); + } + state.rules[rule_id] = rule; + } + + static bool is_word_char(char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '-' || ('0' <= c && c <= '9'); + } + + static std::pair parse_hex(const char * src, int size) { + const char * pos = src; + const char * end = src + size; + uint32_t value = 0; + for ( ; pos < end && *pos; pos++) { + value <<= 4; + char c = *pos; + if ('a' <= c && c <= 'f') { + value += c - 'a' + 10; + } else if ('A' <= c && c <= 'F') { + value += c - 'A' + 10; + } else if ('0' <= c && c <= '9') { + value += c - '0'; + } else { + break; + } + } + if (pos != end) { + throw std::runtime_error("expecting " + std::to_string(size) + " hex chars at " + src); + } + return std::make_pair(value, pos); + } + + static const char * parse_space(const char * src, bool newline_ok) { + const char * pos = src; + while (*pos == ' ' || *pos == '\t' || *pos == '#' || + (newline_ok && (*pos == '\r' || *pos == '\n'))) { + if (*pos == '#') { + while (*pos && *pos != '\r' && *pos != '\n') { + pos++; + } + } else { + pos++; + } + } + return pos; + } + + static const char * parse_name(const char * src) { + const char * pos = src; + while (is_word_char(*pos)) { + pos++; + } + if (pos == src) { + throw std::runtime_error(std::string("expecting name at ") + src); + } + return pos; + } + + static std::pair parse_char(const char * src) { + if (*src == '\\') { + switch (src[1]) { + case 'x': return parse_hex(src + 2, 2); + case 'u': return parse_hex(src + 2, 4); + case 'U': return parse_hex(src + 2, 8); + case 't': return std::make_pair('\t', src + 2); + case 'r': return std::make_pair('\r', src + 2); + case 'n': return std::make_pair('\n', src + 2); + case '\\': + case '"': + case '[': + case ']': + return std::make_pair(src[1], src + 2); + default: + throw std::runtime_error(std::string("unknown escape at ") + src); + } + } else if (*src) { + return decode_utf8(src); + } + throw std::runtime_error("unexpected end of input"); + } + + static const char * parse_alternates( + parse_state & state, + const char * src, + const std::string & rule_name, + uint32_t rule_id, + bool is_nested); + + static const char * parse_sequence( + parse_state & state, + const char * src, + const std::string & rule_name, + std::vector & out_elements, + bool is_nested) { + size_t last_sym_start = out_elements.size(); + const char * pos = src; + while (*pos) { + if (*pos == '"') { // literal string + pos++; + last_sym_start = out_elements.size(); + while (*pos != '"') { + auto char_pair = parse_char(pos); + pos = char_pair.second; + out_elements.push_back({WHISPER_GRETYPE_CHAR, char_pair.first}); + } + pos = parse_space(pos + 1, is_nested); + } else if (*pos == '[') { // char range(s) + pos++; + enum whisper_gretype start_type = WHISPER_GRETYPE_CHAR; + if (*pos == '^') { + pos++; + start_type = WHISPER_GRETYPE_CHAR_NOT; + } + last_sym_start = out_elements.size(); + while (*pos != ']') { + auto char_pair = parse_char(pos); + pos = char_pair.second; + enum whisper_gretype type = last_sym_start < out_elements.size() + ? WHISPER_GRETYPE_CHAR_ALT + : start_type; + + out_elements.push_back({type, char_pair.first}); + if (pos[0] == '-' && pos[1] != ']') { + auto endchar_pair = parse_char(pos + 1); + pos = endchar_pair.second; + out_elements.push_back({WHISPER_GRETYPE_CHAR_RNG_UPPER, endchar_pair.first}); + } + } + pos = parse_space(pos + 1, is_nested); + } else if (is_word_char(*pos)) { // rule reference + const char * name_end = parse_name(pos); + uint32_t ref_rule_id = get_symbol_id(state, pos, name_end - pos); + pos = parse_space(name_end, is_nested); + last_sym_start = out_elements.size(); + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, ref_rule_id}); + } else if (*pos == '(') { // grouping + // parse nested alternates into synthesized rule + pos = parse_space(pos + 1, true); + uint32_t sub_rule_id = generate_symbol_id(state, rule_name); + pos = parse_alternates(state, pos, rule_name, sub_rule_id, true); + last_sym_start = out_elements.size(); + // output reference to synthesized rule + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + if (*pos != ')') { + throw std::runtime_error(std::string("expecting ')' at ") + pos); + } + pos = parse_space(pos + 1, is_nested); + } else if (*pos == '*' || *pos == '+' || *pos == '?') { // repetition operator + if (last_sym_start == out_elements.size()) { + throw std::runtime_error(std::string("expecting preceding item to */+/? at ") + pos); + } + + // apply transformation to previous symbol (last_sym_start to end) according to + // rewrite rules: + // S* --> S' ::= S S' | + // S+ --> S' ::= S S' | S + // S? --> S' ::= S | + uint32_t sub_rule_id = generate_symbol_id(state, rule_name); + std::vector sub_rule; + // add preceding symbol to generated rule + sub_rule.insert( + sub_rule.end(), out_elements.begin() + last_sym_start, out_elements.end()); + if (*pos == '*' || *pos == '+') { + // cause generated rule to recurse + sub_rule.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + } + // mark start of alternate def + sub_rule.push_back({WHISPER_GRETYPE_ALT, 0}); + if (*pos == '+') { + // add preceding symbol as alternate only for '+' (otherwise empty) + sub_rule.insert( + sub_rule.end(), out_elements.begin() + last_sym_start, out_elements.end()); + } + sub_rule.push_back({WHISPER_GRETYPE_END, 0}); + add_rule(state, sub_rule_id, sub_rule); + + // in original rule, replace previous symbol with reference to generated rule + out_elements.resize(last_sym_start); + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + + pos = parse_space(pos + 1, is_nested); + } else { + break; + } + } + return pos; + } + + static const char * parse_alternates( + parse_state & state, + const char * src, + const std::string & rule_name, + uint32_t rule_id, + bool is_nested) { + std::vector rule; + const char * pos = parse_sequence(state, src, rule_name, rule, is_nested); + while (*pos == '|') { + rule.push_back({WHISPER_GRETYPE_ALT, 0}); + pos = parse_space(pos + 1, true); + pos = parse_sequence(state, pos, rule_name, rule, is_nested); + } + rule.push_back({WHISPER_GRETYPE_END, 0}); + add_rule(state, rule_id, rule); + return pos; + } + + static const char * parse_rule(parse_state & state, const char * src) { + const char * name_end = parse_name(src); + const char * pos = parse_space(name_end, false); + size_t name_len = name_end - src; + uint32_t rule_id = get_symbol_id(state, src, name_len); + const std::string name(src, name_len); + + if (!(pos[0] == ':' && pos[1] == ':' && pos[2] == '=')) { + throw std::runtime_error(std::string("expecting ::= at ") + pos); + } + pos = parse_space(pos + 3, true); + + pos = parse_alternates(state, pos, name, rule_id, false); + + if (*pos == '\r') { + pos += pos[1] == '\n' ? 2 : 1; + } else if (*pos == '\n') { + pos++; + } else if (*pos) { + throw std::runtime_error(std::string("expecting newline or end at ") + pos); + } + return parse_space(pos, true); + } + + parse_state parse(const char * src) { + try { + parse_state state; + const char * pos = parse_space(src, true); + while (*pos) { + pos = parse_rule(state, pos); + } + return state; + } catch (const std::exception & err) { + fprintf(stderr, "%s: error parsing grammar: %s\n", __func__, err.what()); + return parse_state(); + } + } + + static void print_grammar_char(FILE * file, uint32_t c) { + if (0x20 <= c && c <= 0x7f) { + fprintf(file, "%c", static_cast(c)); + } else { + // cop out of encoding UTF-8 + fprintf(file, "", c); + } + } + + static bool is_char_element(whisper_grammar_element elem) { + switch (elem.type) { + case WHISPER_GRETYPE_CHAR: return true; + case WHISPER_GRETYPE_CHAR_NOT: return true; + case WHISPER_GRETYPE_CHAR_ALT: return true; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: return true; + default: return false; + } + } + + static void print_rule_binary(FILE * file, const std::vector & rule) { + for (auto elem : rule) { + switch (elem.type) { + case WHISPER_GRETYPE_END: fprintf(file, "END"); break; + case WHISPER_GRETYPE_ALT: fprintf(file, "ALT"); break; + case WHISPER_GRETYPE_RULE_REF: fprintf(file, "RULE_REF"); break; + case WHISPER_GRETYPE_CHAR: fprintf(file, "CHAR"); break; + case WHISPER_GRETYPE_CHAR_NOT: fprintf(file, "CHAR_NOT"); break; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: fprintf(file, "CHAR_RNG_UPPER"); break; + case WHISPER_GRETYPE_CHAR_ALT: fprintf(file, "CHAR_ALT"); break; + } + switch (elem.type) { + case WHISPER_GRETYPE_END: + case WHISPER_GRETYPE_ALT: + case WHISPER_GRETYPE_RULE_REF: + fprintf(file, "(%u) ", elem.value); + break; + case WHISPER_GRETYPE_CHAR: + case WHISPER_GRETYPE_CHAR_NOT: + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + case WHISPER_GRETYPE_CHAR_ALT: + fprintf(file, "(\""); + print_grammar_char(file, elem.value); + fprintf(file, "\") "); + break; + } + } + fprintf(file, "\n"); + } + + static void print_rule( + FILE * file, + uint32_t rule_id, + const std::vector & rule, + const std::map & symbol_id_names) { + if (rule.empty() || rule.back().type != WHISPER_GRETYPE_END) { + throw std::runtime_error( + "malformed rule, does not end with WHISPER_GRETYPE_END: " + std::to_string(rule_id)); + } + fprintf(file, "%s ::= ", symbol_id_names.at(rule_id).c_str()); + for (size_t i = 0, end = rule.size() - 1; i < end; i++) { + whisper_grammar_element elem = rule[i]; + switch (elem.type) { + case WHISPER_GRETYPE_END: + throw std::runtime_error( + "unexpected end of rule: " + std::to_string(rule_id) + "," + + std::to_string(i)); + case WHISPER_GRETYPE_ALT: + fprintf(file, "| "); + break; + case WHISPER_GRETYPE_RULE_REF: + fprintf(file, "%s ", symbol_id_names.at(elem.value).c_str()); + break; + case WHISPER_GRETYPE_CHAR: + fprintf(file, "["); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_NOT: + fprintf(file, "[^"); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + if (i == 0 || !is_char_element(rule[i - 1])) { + throw std::runtime_error( + "WHISPER_GRETYPE_CHAR_RNG_UPPER without preceding char: " + + std::to_string(rule_id) + "," + std::to_string(i)); + } + fprintf(file, "-"); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_ALT: + if (i == 0 || !is_char_element(rule[i - 1])) { + throw std::runtime_error( + "WHISPER_GRETYPE_CHAR_ALT without preceding char: " + + std::to_string(rule_id) + "," + std::to_string(i)); + } + print_grammar_char(file, elem.value); + break; + } + if (is_char_element(elem)) { + switch (rule[i + 1].type) { + case WHISPER_GRETYPE_CHAR_ALT: + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + break; + default: + fprintf(file, "] "); + } + } + } + fprintf(file, "\n"); + } + + void print_grammar(FILE * file, const parse_state & state) { + try { + std::map symbol_id_names; + for (auto kv : state.symbol_ids) { + symbol_id_names[kv.second] = kv.first; + } + for (size_t i = 0, end = state.rules.size(); i < end; i++) { + // fprintf(file, "%zu: ", i); + // print_rule_binary(file, state.rules[i]); + print_rule(file, uint32_t(i), state.rules[i], symbol_id_names); + // fprintf(file, "\n"); + } + } catch (const std::exception & err) { + fprintf(stderr, "\n%s: error printing grammar: %s\n", __func__, err.what()); + } + } + + std::vector parse_state::c_rules() const { + std::vector ret; + for (const auto & rule : rules) { + ret.push_back(rule.data()); + } + return ret; + } +} diff --git a/examples/grammar-parser.h b/examples/grammar-parser.h new file mode 100644 index 0000000000000000000000000000000000000000..47d019c33e15375042c3e61957a520a00b851072 --- /dev/null +++ b/examples/grammar-parser.h @@ -0,0 +1,29 @@ +// Implements a parser for an extended Backus-Naur form (BNF), producing the +// binary context-free grammar format specified by whisper.h. Supports character +// ranges, grouping, and repetition operators. As an example, a grammar for +// arithmetic might look like: +// +// root ::= expr +// expr ::= term ([-+*/] term)* +// term ::= num | "(" space expr ")" space +// num ::= [0-9]+ space +// space ::= [ \t\n]* + +#pragma once +#include "whisper.h" +#include +#include +#include +#include + +namespace grammar_parser { + struct parse_state { + std::map symbol_ids; + std::vector> rules; + + std::vector c_rules() const; + }; + + parse_state parse(const char * src); + void print_grammar(FILE * file, const parse_state & state); +} diff --git a/examples/helpers.js b/examples/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..423bada60bac62a2d214a8c87d7e63667debe320 --- /dev/null +++ b/examples/helpers.js @@ -0,0 +1,191 @@ +// Common Javascript functions used by the examples + +function convertTypedArray(src, type) { + var buffer = new ArrayBuffer(src.byteLength); + var baseView = new src.constructor(buffer).set(src); + return new type(buffer); +} + +var printTextarea = (function() { + var element = document.getElementById('output'); + if (element) element.value = ''; // clear browser cache + return function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + console.log(text); + if (element) { + element.value += text + "\n"; + element.scrollTop = element.scrollHeight; // focus on bottom + } + }; +})(); + +async function clearCache() { + if (confirm('Are you sure you want to clear the cache?\nAll the models will be downloaded again.')) { + indexedDB.deleteDatabase(dbName); + location.reload(); + } +} + +// fetch a remote file from remote URL using the Fetch API +async function fetchRemote(url, cbProgress, cbPrint) { + cbPrint('fetchRemote: downloading with fetch()...'); + + const response = await fetch( + url, + { + method: 'GET', + } + ); + + if (!response.ok) { + cbPrint('fetchRemote: failed to fetch ' + url); + return; + } + + const contentLength = response.headers.get('content-length'); + const total = parseInt(contentLength, 10); + const reader = response.body.getReader(); + + var chunks = []; + var receivedLength = 0; + var progressLast = -1; + + while (true) { + const { done, value } = await reader.read(); + + if (done) { + break; + } + + chunks.push(value); + receivedLength += value.length; + + if (contentLength) { + cbProgress(receivedLength/total); + + var progressCur = Math.round((receivedLength / total) * 10); + if (progressCur != progressLast) { + cbPrint('fetchRemote: fetching ' + 10*progressCur + '% ...'); + progressLast = progressCur; + } + } + } + + var position = 0; + var chunksAll = new Uint8Array(receivedLength); + + for (var chunk of chunks) { + chunksAll.set(chunk, position); + position += chunk.length; + } + + return chunksAll; +} + +// load remote data +// - check if the data is already in the IndexedDB +// - if not, fetch it from the remote URL and store it in the IndexedDB +function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) { + if (!navigator.storage || !navigator.storage.estimate) { + cbPrint('loadRemote: navigator.storage.estimate() is not supported'); + } else { + // query the storage quota and print it + navigator.storage.estimate().then(function (estimate) { + cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes'); + cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes'); + }); + } + + // check if the data is already in the IndexedDB + var rq = indexedDB.open(dbName, dbVersion); + + rq.onupgradeneeded = function (event) { + var db = event.target.result; + if (db.version == 1) { + var os = db.createObjectStore('models', { autoIncrement: false }); + cbPrint('loadRemote: created IndexedDB ' + db.name + ' version ' + db.version); + } else { + // clear the database + var os = event.currentTarget.transaction.objectStore('models'); + os.clear(); + cbPrint('loadRemote: cleared IndexedDB ' + db.name + ' version ' + db.version); + } + }; + + rq.onsuccess = function (event) { + var db = event.target.result; + var tx = db.transaction(['models'], 'readonly'); + var os = tx.objectStore('models'); + var rq = os.get(url); + + rq.onsuccess = function (event) { + if (rq.result) { + cbPrint('loadRemote: "' + url + '" is already in the IndexedDB'); + cbReady(dst, rq.result); + } else { + // data is not in the IndexedDB + cbPrint('loadRemote: "' + url + '" is not in the IndexedDB'); + + // alert and ask the user to confirm + if (!confirm( + 'You are about to download ' + size_mb + ' MB of data.\n' + + 'The model data will be cached in the browser for future use.\n\n' + + 'Press OK to continue.')) { + cbCancel(); + return; + } + + fetchRemote(url, cbProgress, cbPrint).then(function (data) { + if (data) { + // store the data in the IndexedDB + var rq = indexedDB.open(dbName, dbVersion); + rq.onsuccess = function (event) { + var db = event.target.result; + var tx = db.transaction(['models'], 'readwrite'); + var os = tx.objectStore('models'); + + var rq = null; + try { + var rq = os.put(data, url); + } catch (e) { + cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB: \n' + e); + cbCancel(); + return; + } + + rq.onsuccess = function (event) { + cbPrint('loadRemote: "' + url + '" stored in the IndexedDB'); + cbReady(dst, data); + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB'); + cbCancel(); + }; + }; + } + }); + } + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to get data from the IndexedDB'); + cbCancel(); + }; + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to open IndexedDB'); + cbCancel(); + }; + + rq.onblocked = function (event) { + cbPrint('loadRemote: failed to open IndexedDB: blocked'); + cbCancel(); + }; + + rq.onabort = function (event) { + cbPrint('loadRemote: failed to open IndexedDB: abort'); + cbCancel(); + }; +} diff --git a/examples/json.hpp b/examples/json.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d1a37ad7cb874769d911fc3362d567da3aca291 --- /dev/null +++ b/examples/json.hpp @@ -0,0 +1,24596 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _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, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template